define(['js/charts' + $E.jsv], function(Charts) {
	/*
	 * 转换坐标点
	 */
	var aligns = ['align_left', 'align_center', 'align_right'],

	transferPoint = function(profile) {
		profile.left = parseFloat(profile.cs[0] / 15);
		profile.top = parseFloat(profile.cs[1] / 15);
		profile.width = parseFloat(profile.cs[2] / 15);
		profile.height = parseFloat(profile.cs[3] / 15);
		profile.lWidth = parseFloat(profile.lw / 15);
	},

	randArray = function(data) {
		// 获取数组长度
		var arrlen = data.length;
		// 创建数组, 存放下标数
		var try1 = new Array();
		for (var i = 0; i < arrlen; i++) {
			try1[i] = i;
		}
		// 创建数组, 生成随机下标数
		var try2 = new Array();
		for (var i = 0; i < arrlen; i++) {
			try2[i] = try1.splice(Math.floor(Math.random() * try1.length), 1);
		}
		// 创建数组, 生成对应随机下标数的数组
		var try3 = new Array();
		for (var i = 0; i < arrlen; i++) {
			try3[i] = data[try2[i]];
		}
		return try3;
	},

	rollArray = function(data) {
		var rs = [];
		if (data.length > 0) {
			if (data.length > 1) {
				for(var i=1; i<data.length; i++) {
					rs.push(data[i]);
				}
			}
			rs.push(data[0]);
		}
		return rs;
	},

	/*
	 * 获取当前控件的风格属性
	 */
	ctlStyle = function(ctl) {
		transferPoint(ctl.profile);
		var style = {
			left : ctl.profile.left + 'px',
			top : ctl.profile.top + 'px',
			width : ctl.profile.width + 'px',
			height : ctl.profile.height + 'px'
		};
		if (ctl.profile._percentSize) {
			style = ctl.profile._percentSize;
		}
		if (ctl.profile.fn && ctl.profile.fn != '宋体')
			style['font-family'] = ctl.profile.fn;
		if (ctl.profile.fs)
			style['font-size'] = ctl.profile.fs + 'px';
		if (ctl.profile.fb)
			style['font-weight'] = 'bolder';
		if (ctl.profile.cr)
			style['color'] = '#' + ctl.profile.cr;
		if (ctl.profile.br)
			style['background-color'] = '#' + ctl.profile.br;

		var outerStyle = {}, innerStyle = {};
		if (ctl.profile.csy) {
			var rs, csy = ctl.profile.csy.split(';');
			$.each(csy, function(i, v){
				rs = v.split(':');
				if (rs.length > 1) {
					if (! rs[0].startWith('@'))
						outerStyle[rs[0].trim()] = rs[1].trim();
					else
						innerStyle[rs[0].substring(1).trim()] = rs[1].trim();
				}
			});
		}

		var clazz = ['dyn_ctl'];
		if (ctl.profile.sty)
			clazz.push(ctl.profile.sty);
		if (ctl.custProp.s_float) {
			// 浮动状态，默认无浮动
			style['float'] = ctl.custProp.s_float;
			style['left'] = style['top'] = undefined;
			//style['position'] = 'static';
			style['position'] = 'relative'
		} else {
			if (ctl.custProp.s_pos) {
				// 定位状态，默认相对定位
				style['position'] = ctl.custProp.s_pos;
				if (ctl.custProp.s_pos == 'relative' || ctl.custProp.s_pos == 'static')
					style['left'] = style['top'] = undefined;
			}
		}
		if (ctl.custProp.s_width) {
			if (ctl.custProp.s_width == '-1')
				style['width'] = undefined;
			else
				style['width'] = ctl.custProp.s_width;
		}
		if (ctl.custProp.s_height) {
			if (ctl.custProp.s_height == '-1')
				style['height'] = undefined;
			else
				style['height'] = ctl.custProp.s_height;
		}
		if (ctl.custProp.s_overflow)
			style['overflow'] = ctl.custProp.s_overflow;
		if (ctl.custProp.s_display)
			style['display'] = ctl.custProp.s_display;
		if (ctl.custProp.s_flexflow)
			style['flex-flow'] = ctl.custProp.s_flexflow;
		if (ctl.custProp.s_justify)
			style['justify-content'] = ctl.custProp.s_justify;
		if (ctl.custProp.s_flex !== undefined)
			style['flex'] = ctl.custProp.s_flex;

		if (ctl.custProp.s_right !== undefined) {
			style['right'] = ctl.custProp.s_right;
		}
		if (ctl.custProp.s_bottom !== undefined) {
			style['bottom'] = ctl.custProp.s_bottom;
		}
		if (ctl.custProp.s_repos == 1)
			style['left'] = undefined;
		else if (ctl.custProp.s_repos == 2)
			style['top'] = undefined;
		else if (ctl.custProp.s_repos == 3) {
			style['left'] = undefined;
			style['top'] = undefined;
		}

		return {
			style: style,
			outerStyle: outerStyle,
			innerStyle: innerStyle,
			clazz: clazz
		}
	},

	getStyles = function() {
		if (arguments.length < 1)
			return '';

		var s = '', key, style;
		for(var i = 0; i<arguments.length; i ++) {
			style = arguments[i];
			for (key in style) {
				if (style[key] !== undefined)
					s += ";" + key + ":" + style[key];
			}
		}
		if (s.length > 0)
			return s.substring(1);
		else
			return s;
	},
	getStyleAttr = function() {
		if (arguments.length < 2)
			return undefined;

		var key, style, attr;
		for(var i = 1; i<arguments.length; i ++) {
			style = arguments[i];
			for (key in style) {
				if (key == arguments[0])
					attr = style[key];
			}
		}
		return attr;
	},

	ctlLabelWidth = function(profile) {
		return profile.lWidth > 0? profile.lWidth + 3 : 0;
	},

	rmMarks = function(str) {
		if (str.startWith("'"))
			str = str.substring(1);
		if (str.endWith("'"))
			str = str.substring(0, str.length-1);
		return str;
	},

	kvCtl_getOptions = function(ctl, cacheId, sqlId, params, keyField, valueField, value) {
		ctl.runtime.sqlQueue[sqlId] = {
			structId : ctl.runtime.struct.id,
			params : params,
			callback : function(data) {
				// console.log(data);
				var paramsStr = $F.display(params);
				if (data.count == -1) {
					//console.log(ctl.profile);
					$F.err('SQLExec - failed', 'DYN[' + ctl.runtime.struct.id + '] KEY[' + sqlId + '], 控件[' + ctl.type + '@' + ctl.id + '][PARAMS: ' + paramsStr + ']');
					ctl.setOptions(keyField, valueField, {columns:[], fields:[]}, '');
				} else {
					if ($E.debug)
						console.log('SQLExec - success', 'DYN[' + ctl.runtime.struct.id + '] KEY[' + sqlId + '], 控件[' + ctl.type + '@' + ctl.id + '][PARAMS: ' + paramsStr + ']');
					//console.log(data);
					if (cacheId) {
						// 缓存结果
						ctl.instance.project.cache[cacheId] = data;
					}
					ctl.setOptions(keyField, valueField, data, value);
				}
			},
			error : function(message) {
				$F.err('SQLExec - failed', 'DYN[' + ctl.runtime.struct.id + ']: ' + message);
				ctl.setOptions(keyField, valueField, [], '');
			}
		}
	},

	fireEvent = function(ctl, cmdId, cmds, ev) {
		//当这个simple扩展属性是true时候，不试用异步方式，直接执行此命令，避免了有些命令（如File.upload）上下文变化后，就执行无效的问题
		if (ctl.custProp.simple)
			ctl.instance.dc.doCmdList(cmdId + '.sync', cmds, '', ev, ctl.runtime);
		else {
			$F.process(function(){
				//console.log('fireEvent start');
				if (ctl.instance) {
					//此处需要判断一下，可能触发此命令的时候ctl.instance已经被清空了
					ctl.instance.dc.doCmdList(cmdId, cmds, '', ev, ctl.runtime);
				}
				//console.log('fireEvent completed.');
			})
		}

	},

	/**
	 * 注册控件的消息事务
	 */
	registerEvents = function(ctl, cmds, xitemEv) {
		if (ctl.profile.vV) {
			// 绑定了变量的控件，值改变时触发消息通知给实例
			if (ctl.type !== 'TABLE' && ctl.type !== 'TABLE2') {
				ctl.bind('change', function(e){
					ctl.instance.fireValue(ctl.profile.vV, ctl.runtime, ctl.evt(), ctl);
				});
			}
		}

		// 注册控件命令
		if (! cmds)
			return;
		for(var key in cmds) {
			if (key == 'P3') {
				if (ctl.type == 'BUTTON' || ctl.type == 'CHECKBOX' || ctl.type == 'RADIO'
					|| ctl.type == 'IMAGE' || ctl.type == 'LINK' || ctl.type == 'CHART'
					|| ctl.type == 'LABEL' || ctl.type == 'SCRIPT' || ctl.type == 'TIMELINE') {
					ctl.bind('click', function(e, obj) {
						ctl.disable(true);
						if (obj === undefined)
							obj = xitemEv.XITEM;
						else if (Object.keys(obj).length == 0)
							$.extend(obj, xitemEv.XITEM)
						fireEvent(ctl, 'P3@' + ctl.id, cmds['P3'], $.extend({CTRL: ctl, IEVENT: e, EVENT: obj}, xitemEv));
						ctl.disable(false);
					})
				} else {
					ctl.bind('change', function(e, obj) {
						if (obj === undefined)
							obj = xitemEv.XITEM;
						else if (Object.keys(obj).length == 0)
							$.extend(obj, xitemEv.XITEM)
						fireEvent(ctl, 'P3@' + ctl.id, cmds['P3'], $.extend({CTRL: ctl, IEVENT: e, EVENT: obj}, xitemEv));
					})
				}
			}
			else if (key == 'P4') {
				ctl.bind('dblclick', function(e, obj) {
					if (obj === undefined)
						obj = xitemEv.XITEM;
					else if (Object.keys(obj).length == 0)
						$.extend(obj, xitemEv.XITEM)
					fireEvent(ctl, 'P4@' + ctl.id, cmds['P4'], $.extend({CTRL: ctl, IEVENT: e, EVENT: obj}, xitemEv));
				})
			}
			else if (key == 'P5') {
				ctl.bind('keydown', function(e) {
					if (e.keyCode == 13)
						fireEvent(ctl, 'P5@' + ctl.id, cmds['P5'], $.extend({CTRL: ctl, IEVENT: e, EVENT: {
							VALUE: ctl.val()
						}}, xitemEv));
				})
			}
			else if (key == 'P6') {
				ctl.bind('focus', function(e, obj) {
					if (obj === undefined)
						obj = xitemEv.XITEM;
					else if (Object.keys(obj).length == 0)
						$.extend(obj, xitemEv.XITEM)
					fireEvent(ctl, 'P6@' + ctl.id, cmds['P6'], $.extend({CTRL: ctl, IEVENT: e, EVENT: obj}, xitemEv));
				})
			}
			else if (key == 'P7') {
				ctl.bind('blur', function(e, obj) {
					if (obj === undefined)
						obj = xitemEv.XITEM;
					else if (Object.keys(obj).length == 0)
						$.extend(obj, xitemEv.XITEM)
					fireEvent(ctl, 'P7@' + ctl.id, cmds['P7'], $.extend({CTRL: ctl, IEVENT: e, EVENT: obj}, xitemEv));
				})
			}
			else {
				if (key < 'P10000')
					return $F.err('Ctls - registerEvents', '无效的命令号：' + key);
			}
		}
	},

	makeValueAndState = function(ctl, data, rowNum, notval) {
		var instance = ctl.instance,
			runtime = ctl.runtime,
			xitemEv = {},
			ctlCmds = runtime.struct.CtlCmdList[ctl.profile.cId];

		if (ctlCmds && ctlCmds['P55']) {
			// 执行控件的渲染时命令
			$F.logGroup('执行控件绘制前命令:' + runtime.struct.id + '.' + ctl.id)
			// console.log(runtime)
			instance.dc.doCmdList('P55@' + ctl.path, ctlCmds['P55'], '', {CTRL: ctl}, runtime);
			$F.logGroupEnd();
		}

		registerEvents(ctl, ctlCmds, xitemEv);

		if (! $F.isNull(data)) {
			// XITEM控件，直接取数值展示
			if (ctl.profile.rl)
				if (data.length > ctl.profile.rl -1) {
					ctl.val(data[ctl.profile.rl-1]);
				}
			$.extend(xitemEv, {
				XITEM: {
					ROWDATA: data,
					GRIDROW: rowNum + 1,
					GRIDCOL: ctl.profile.rl
				}
			});
		} else {
			// 绑定值消息，当实例改变时，控件同步更新
			if (ctl.profile.vV) {
				if (ctl.objProp && ctl.objProp.sv !== undefined && ctl.objProp.ss) {
					// 通过监听变量进行风格变化
					ctl.toggle(instance.getValue(ctl.profile.vV, runtime));
					instance.bindValue(ctl.profile.vV, ctl, function(e) {
						ctl.toggle(e.data);
					});
				} else {
					if (! notval)
						ctl.val(instance.getValue(ctl.profile.vV, runtime));
					instance.bindValue(ctl.profile.vV, ctl, function(e) {
						ctl.evt(e);
					});
				}
			}
		}

		// 绑定状态消息，当实例改变时，控件状态更新
		if (ctl.profile.sV) {
			ctl.state(instance.getValue(ctl.profile.sV, runtime));
			instance.bindValue(ctl.profile.sV, ctl, function(e) {
				ctl.state(e.data);
			});
		}

		if (ctlCmds && ctlCmds['P56']) {
			// 执行控件的渲染时命令
			$F.logGroup('执行控件绘制后命令:' + runtime.struct.id + '.' + ctl.id)
			// console.log(runtime)
			instance.dc.doCmdList('P56@' + ctl.path, ctlCmds['P56'], '', {CTRL: ctl}, runtime);
			$F.logGroupEnd();
		}
	},

	getValue = function(instance, propertyName, runtime) {
		if (propertyName.indexOf('.') == -1) {
			// 引用全局变量
			var project = instance.project;
			switch(propertyName.toUpperCase()) {
			case 'EPID':
			case 'C_EPID':
				return $E.staff.epid;
			case 'EPIDTB':
			case 'C_EPIDTB':
				return $E.staff.epidSql;
			case 'STAFFID':
			case 'C_BY':
				return $E.staff.id;
			case 'STAFFNAME':
				return $E.staff.name;
			case 'AGENTID':
				return $E.staff.agentId;
			case 'ROLEGROUPID':
			case 'C_GRP':
				return project.groupId;
			case 'ROLEGROUPNAME':
				return project.groupName;
			case 'ANI':
			case 'DNIS':
			case 'EXTENSION':
				if (project.cwInfo && project.cwInfo.callInfo && project.cwInfo.callInfo.getValue) {
					return project.cwInfo.callInfo.getValue(propertyName.toLowerCase());
				} else
					return '';
			case 'CALLTYPE':
				if (project.cwInfo)
					return project.cwInfo.callType;
				else
					return '';
			case 'CUREVENTID':
				if (project.cwInfo)
					return project.cwInfo.eventGuid;
				else
					return '';
			case 'G_ISSUPER':
				var isSupervisor = parseInt(project.getParam('ISSUPE', 2));
				return ($E.staff.supervisor > isSupervisor) ? 1 : 0;
			case 'G_SFASHA':
				return parseInt(project.getParam('SFASHA', 0));
			default:
				if (propertyName.startWith("OBJ_")) {
					propertyName = propertyName.substring(4);
					return instance.objective.getValue(propertyName);
				} else if (propertyName.startWith("CUST_")) {
					propertyName = propertyName.substring(5);
					return instance.customer.getValue(propertyName);
				}
			}
		} else
			return instance.getValue(propertyName, runtime);
	},

	sqldata = function(data, fields) {
		if (!data || !data.columns) {
			$F.err('Ctls - sqldata', '无效的数据对象');
			return [];
		}
		// console.log(data);
		var idxs = [], idx;
		for(var i=0; i<fields.length; i++) {
			idx = data.columns.indexOf(fields[i].toUpperCase());
			if (idx == -1) {
				$F.err('Ctls - sqldata', "数据结果中不存在列名: " + fields[i]);
				return [];
			}
			idxs.push(idx);
		}

		var result = [], rs;
		$.each(data.fields, function(i, v) {
			rs = {};
			$.each(idxs, function(i2, idx) {
				rs[fields[i2]] = v[idx];
			})
			result.push(rs);
		});
		return result;
	},

	getPowerPersenalize = function(runtime, id) {
		var powers = runtime._POWER;
		if (powers) {
			return powers[id];
		}
		return null;
	},

	/**
	 * 执行某个控件的命令组
	 */
	doCmd = function(ctl, cmdId, values) {
		if (! cmdId.startWith('P'))
			cmdId = 'P' + cmdId;

		var id = ctl.id, o = id.indexOf('-');
		if (o !== -1)
			id = id.substring(0, o);
		var ctlCmds = ctl.runtime.struct.CtlCmdList[id];
		if (ctlCmds && ctlCmds[cmdId]) {
			if (values)
				values.CTRL = ctl;
			else
				values = {CTRL: ctl}
			ctl.instance.dc.doCmdList(cmdId + '@' + ctl.path, ctlCmds[cmdId], '', values, ctl.runtime);
		}
	};

	/*
	 * 动态页面组件：Number<br/>
	 * 该组件包括：整形和浮点型
	 */
	var cNumber = function(container, profile, runtime, data, rowNum) {
		return new ctlNumber(container, profile, runtime, data, rowNum);
	},

	ctlNumber = function(container, profile, runtime, data, rowNum) {
		var a = this;
		a.id = profile.cId + (rowNum == undefined? '' : ('-' + rowNum));
		a.type = "NUMBER";
		a.disabled = false;
		a.instance = runtime.instance;
		a.container = container;
		a.runtime = runtime;
		a.path = runtime.namespace + '.' + a.id;
		a.profile = profile;
		a.objProp = profile.ot || {};
		a.custProp = profile.o2 || {};
		a.xitemRow = rowNum;
		a.parentDisabled = a.disabled = false;
		a.attributes = {};
		//console.log(a);

		var q = ctlStyle(a), style = q.style, outerStyle = q.outerStyle, innerStyle = q.innerStyle, clazz = q.clazz, attrs= '';
		if (a.objProp.ri)
			clazz.push('dyn_rtl');
		if (a.objProp.h)
			attrs += ' placeholder="' + (a.objProp.h || '') + '"';
		if (a.custProp.required)
			attrs += ' required="required"'

		innerStyle['font-size'] = 'inherit';
		if (profile.lWidth > 0) {
			// 带标签控件
			clazz.push('wl');
			a.dom = $('<div data-type="' + a.type + '" data-path="' + a.path + '" class="' + clazz.join(' ') + '" style="' + getStyles(style, outerStyle) + '" />').appendTo(container);
			var fakeBox = (a.dom.css('display') == 'flex') ? a.dom : ($('<div class="wl" />').appendTo(a.dom));
			a.lb = $('<span class="dyn_as dyn_label" style="width:' + profile.lWidth + 'px; line-height:' + style['height'] + '"/>').text(profile.lD).appendTo(fakeBox);
			a.input = $('<input type="text" size=1 class="wlc" style="' + getStyles(innerStyle) + '"' + attrs + '/>').appendTo(fakeBox);
		} else {
			if (style['width'] == 'auto' || style['height'] == 'auto') {
				a.dom = $('<div data-type="' + a.type + '" data-path="' + a.path + '" class="' + clazz.join(' ') + '" style="' + getStyles(style, outerStyle) + '" />').appendTo(container);
				a.input = $('<input type="text" style="' + getStyles(innerStyle) + ';width:100%;height:100%"' + attrs + '/>').appendTo(a.dom);
			} else
				a.dom = a.input = $('<input type="text" data-type="' + a.type + '" data-path="' + a.path + '" class="' + clazz.join(' ') + '" style="' + getStyles(style, outerStyle, innerStyle) + '"' + attrs + '/>').appendTo(container);
		}
		if (a.custProp.placeholder)
			a.input.attr('placeholder', a.custProp.placeholder)

		// objProp.sz 是否在数字为空的时候显示0，默认为不显示
		Helper.makeNumberInput(a.input, a.objProp.sz, a.custProp.format);

		if (a.custProp.entercmd) {
			a.input.on('keyup', function(e) {
				if (e.keyCode == 13) {
					a.instance.doCmd('P' + a.custProp.entercmd, {
						EVENT: {
							VALUE: a.input.val()
						}
					}, a.runtime, a.id)
					e.stopPropagation();
				}
			})
		}

		if (a.custProp.s_state)
			a.state(a.custProp.s_state);
		makeValueAndState(a, data, rowNum);
		return a;
	};

	ctlNumber.prototype = {
		state : function(e) {
			if (e == undefined)
				return this._state;
			else {
				this._state = e;
				if (e == 1)
					this.dom.hide();
				else {
					this.dom.show();
					this.disable(e == 2);
					this.input.prop('readonly', (e == 3));
				}
			}
		},
		disable: function(e, byParent) {
			if (byParent) {
				this.input.prop('disabled', e || this.disabled);
				this.parentDisabled = e;
			} else {
				this.input.prop('disabled', e || this.parentDisabled);
				this.disabled = e;
			}
		},

		val : function(t) {
			var a = this;
			if (t == undefined) {
				return a.instance.getValueByPropertyName(a.runtime, a.profile.vV, a.input.val());
			} else {
				a.input.val(a.objProp.sz ? (t || 0) : (t || '') );
				a.input.trigger('blur');
				return a;
			}
		},
		evt : function(e) {
			if (e == undefined) {
				return {
					type: 0,
					data: this.val()
				}
			} else
				this.val(e.data);
		},

		bind : function(e, callback) {
			this.input.bind(e, callback);
		},

		triggerChange : function(e) {
			this.input.trigger('change');
		},

		focus : function() {
			this.input.focus();
		},

		driftLayer : function(layer) {
			var owner = this.input;
			layer.drift(owner.offset().top, owner.offset().left, owner.offset().top + owner.outerHeight(), owner.offset().left + owner.outerWidth());
		},

		setStyle : function(cssStyle) {
			this.input.css(cssStyle);
		},

		label : function(e) {
			if (e == undefined)
				return (this.label ? this.label.text() : '');
			else {
				this.label && this.label.text(e);
				return this;
			}
		},
		getItem: function(e) {
			return this.attributes[e];
		},
		setItem: function(e, v) {
			this.attributes[e] = v;
			return this;
		}

	};

	/*
	 * 动态页面组件：Numbox<br/>
	 * 该组件包括：整型
	 */
	var cPin = function(container, profile, runtime, data, rowNum) {
		return new ctlPin(container, profile, runtime, data, rowNum);
	},

	ctlPin = function(container, profile, runtime, data, rowNum) {
		var a = this;
		a.id = profile.cId + (rowNum == undefined? '' : ('-' + rowNum));
		a.type = "PIN";
		a.disabled = false;
		a.instance = runtime.instance;
		a.container = container;
		a.runtime = runtime;
		a.path = runtime.namespace + '.' + a.id;
		a.profile = profile;
		a.objProp = profile.ot || {};
		a.custProp = profile.o2 || {};
		a.xitemRow = rowNum;
		a.parentDisabled = a.disabled = false;
		a.attributes = {};
		//console.log(a);

		var q = ctlStyle(a), style = q.style, outerStyle = q.outerStyle, innerStyle = q.innerStyle, clazz = q.clazz, attrs= '';
		if (a.objProp.ri)
			clazz.push('dyn_rtl');
		if (a.objProp.h)
			attrs += ' placeholder="' + (a.objProp.h || '') + '"';
		if (a.custProp.required)
			attrs += ' required="required"'

		innerStyle['font-size'] = 'inherit';
		if (profile.lWidth > 0) {
			// 带标签控件
			clazz.push('wl');
			a.dom = $('<div data-type="' + a.type + '" data-path="' + a.path + '" class="' + clazz.join(' ') + '" style="' + getStyles(style, outerStyle) + '" />').appendTo(container);
			var fakeBox = (a.dom.css('display') == 'flex') ? a.dom : ($('<div class="wl" />').appendTo(a.dom));
			a.lb = $('<span class="dyn_as dyn_label" style="width:' + profile.lWidth + 'px; line-height:' + style['height'] + '"/>').text(profile.lD).appendTo(fakeBox);
			var box = $('<div class="numbox"><div class="minus border radius"><span>-</span></div></div>').appendTo(fakeBox);
			a.input = $('<input type="text" class="wlc alignment" style="' + getStyles(innerStyle) + ';width:100%;height:100%"' + attrs + '/>').appendTo(box);
			box.append('<div class="plus border radius"><span>+</span></div>')
			//a.input = $('<input type="text" size=1 class="wlc" style="' + getStyles(innerStyle) + '"' + attrs + '/>').appendTo(fakeBox);
		} else {
			a.dom = $('<div data-type="' + a.type + '" data-path="' + a.path + '" class="' + clazz.join(' ') + '" style="' + getStyles(style, outerStyle) + '" />').appendTo(container);
			var box = $('<div class="numbox"><div class="minus border radius"><span>-</span></div></div>').appendTo(a.dom);
			a.input = $('<input type="text" class="alignment" style="' + getStyles(innerStyle) + ';width:100%;height:100%"' + attrs + '/>').appendTo(box);
			box.append('<div class="plus border radius"><span>+</span></div>')
		}
		if (a.custProp.placeholder)
			a.input.attr('placeholder', a.custProp.placeholder)

		// objProp.sz 是否在数字为空的时候显示0，默认为不显示
		Helper.makeNumberInput(a.input, a.objProp.sz, a.custProp.format);

		if (a.custProp.entercmd) {
			a.input.on('keyup', function(e) {
				if (e.keyCode == 13) {
					a.instance.doCmd('P' + a.custProp.entercmd, {
						EVENT: {
							VALUE: a.input.val()
						}
					}, a.runtime, a.id)
					e.stopPropagation();
				}
			})
		}

		if (a.custProp.s_state)
			a.state(a.custProp.s_state);
		$('.numbox>div', a.dom).on('click', function(e) {
			var x = parseInt(a.input.val());
			if (isNaN(x))
				x = 0;
			if ($(e.currentTarget).hasClass('plus'))
				x ++;
			else
				x --;
			a.input.val(x);
		})
		makeValueAndState(a, data, rowNum);
		return a;
	};

	ctlPin.prototype = {
		state : function(e) {
			if (e == undefined)
				return this._state;
			else {
				this._state = e;
				if (e == 1)
					this.dom.hide();
				else {
					this.dom.show();
					this.disable(e == 2);
					this.input.prop('readonly', (e == 3));
				}
			}
		},
		disable: function(e, byParent) {
			if (byParent) {
				this.input.prop('disabled', e || this.disabled);
				this.parentDisabled = e;
			} else {
				this.input.prop('disabled', e || this.parentDisabled);
				this.disabled = e;
			}
		},

		val : function(t) {
			var a = this;
			if (t == undefined) {
				return a.instance.getValueByPropertyName(a.runtime, a.profile.vV, a.input.val());
			} else {
				a.input.val(a.objProp.sz ? (t || 0) : (t || '') );
				a.input.trigger('blur');
				return a;
			}
		},
		evt : function(e) {
			if (e == undefined) {
				return {
					type: 0,
					data: this.val()
				}
			} else
				this.val(e.data);
		},

		bind : function(e, callback) {
			this.input.bind(e, callback);
		},

		triggerChange : function(e) {
			this.input.trigger('change');
		},

		focus : function() {
			this.input.focus();
		},

		driftLayer : function(layer) {
			var owner = this.dom;
			layer.drift(owner.offset().top, owner.offset().left, owner.offset().top + owner.outerHeight(), owner.offset().left + owner.outerWidth());
		},

		setStyle : function(cssStyle) {
			this.input.css(cssStyle);
		},

		label : function(e) {
			if (e == undefined)
				return (this.label ? this.label.text() : '');
			else {
				this.label && this.label.text(e);
				return this;
			}
		},
		getItem: function(e) {
			return this.attributes[e];
		},
		setItem: function(e, v) {
			this.attributes[e] = v;
			return this;
		}

	};

	/*
	 * 动态页面组件：Text
	 */
	var cText = function(container, profile, runtime, data, rowNum) {
		return new ctlText(container, profile, runtime, data, rowNum);
	},

	ctlText = function(container, profile, runtime, data, rowNum) {
		var a = this;
		a.id = profile.cId + (rowNum == undefined? '' : ('-' + rowNum));
		a.type = "TEXT";
		a.disabled = false;
		a.instance = runtime.instance;
		a.container = container;
		a.runtime = runtime;
		a.path = runtime.namespace + '.' + a.id;
		a.profile = profile;
		a.objProp = profile.ot || {};
		a.custProp = profile.o2 || {};
		a.xitemRow = rowNum;
		a.xitemData = data;
		a.parentDisabled = a.disabled = false;
		a.attributes = {};
		//console.log(a);

		var q = ctlStyle(a), style = q.style, outerStyle = q.outerStyle, innerStyle = q.innerStyle, clazz = q.clazz, attrs = '';
		if (a.objProp.ri)
			clazz.push('dyn_rtl');
		if (a.objProp.h)
			attrs += ' placeholder="' + (a.objProp.h || '') + '"';
		if (a.custProp.required)
			attrs += ' required="required"';

		if (a.objProp.type < 4) {
			var fakeBox;
			// 单行及密码
			if (profile.lWidth > 0) {
				// 带标签控件
				if (! innerStyle['font-size'])
					innerStyle['font-size'] = 'inherit';
				if (! innerStyle['font-family'])
					innerStyle['font-family'] = 'inherit';
				clazz.push('wl');
				a.dom = $('<div data-type="' + a.type + '" data-path="' + a.path + '" class="' + clazz.join(' ') + '" style="' + getStyles(style, outerStyle) + '" />').appendTo(container);
				fakeBox = (a.dom.css('display') == 'flex') ? a.dom : ($('<div class="wl" />').appendTo(a.dom));
				a.lb = $('<span class="dyn_as dyn_label" style="width:' + profile.lWidth + 'px; line-height:' + style['height'] + '"/>').text(profile.lD).appendTo(fakeBox);
				if (a.custProp.actbtn || a.objProp.type == 3) // 带有右侧帮助按钮
					a.form = fakeBox = $('<div class="wlc dyn_input_form" />').appendTo(fakeBox);
				if (a.objProp.type == 0 || a.objProp.type == 3)
					a.input = $('<input type="text" size=1 class="wlc" style="' + getStyles(innerStyle) + '"' + attrs + '/>').appendTo(fakeBox);
				else if (a.objProp.type == 1)
					a.input = $('<input type="password" size=1 class="wlc" style="' + getStyles(innerStyle) + '"' + attrs + '/>').appendTo(fakeBox);
				else if (a.objProp.type == 2)
					a.input = $('<textarea class="wlc" style="' + getStyles(innerStyle) + '"' + attrs + '/>').appendTo(fakeBox);
			} else {
				if (a.custProp.actbtn || a.objProp.type == 3) {
					// 带有右侧帮助按钮
					a.form = fakeBox = a.dom = $('<div data-type="' + a.type + '" data-path="' + a.path + '" class="dyn_input_form ' + clazz.join(' ') + '" style="' + getStyles(style, outerStyle) + '" />').appendTo(container);
					if (a.objProp.type == 0 || a.objProp.type == 3)
						a.input = $('<input type="text" style="' + getStyles(innerStyle) + '"' + attrs + '/>').appendTo(fakeBox);
					else if (a.objProp.type == 1)
						a.input = $('<input type="password" style="' + getStyles(innerStyle) + '"' + attrs + '/>').appendTo(fakeBox);
					else if (a.objProp.type == 2)
						a.input = $('<textarea type="text" style="' + getStyles(innerStyle) + '"' + attrs + '/>').appendTo(fakeBox);
				} else {
					if (style['width'] == 'auto' || style['height'] == 'auto') {
						a.dom = $('<div data-type="' + a.type + '" data-path="' + a.path + '" class="' + clazz.join(' ') + '" style="' + getStyles(style, outerStyle) + '" />').appendTo(container);
						if (a.objProp.type == 0 || a.objProp.type == 3)
							a.input = $('<input type="text" style="' + getStyles(innerStyle) + ';width:100%;height:100%"' + attrs + '/>').appendTo(a.dom);
						else if (a.objProp.type == 1)
							a.input = $('<input type="password" style="' + getStyles(innerStyle) + ';width:100%;height:100%"' + attrs + '/>').appendTo(a.dom);
						else if (a.objProp.type == 2)
							a.input = $('<textarea style="width:100%;height:100%;' + getStyles(innerStyle) + '"' + attrs + '/>').appendTo(a.dom);
					} else {
						if (a.objProp.type == 0 || a.objProp.type == 3)
							a.dom = a.input = $('<input type="text" data-type="' + a.type + '" data-path="' + a.path + '" class="' + clazz.join(' ') + '" style="' + getStyles(style, outerStyle, innerStyle) + '"' + attrs + '/>').appendTo(container);
						else if (a.objProp.type == 1)
							a.dom = a.input = $('<input type="password" data-type="' + a.type + '" data-path="' + a.path + '" class="' + clazz.join(' ') + '" style="' + getStyles(style, outerStyle, innerStyle) + '"' + attrs + '/>').appendTo(container);
						else if (a.objProp.type == 2) {
							a.dom = a.input = $('<textarea data-type="' + a.type + '" data-path="' + a.path + '" class="' + clazz.join(' ') + '" style="' + getStyles(style, outerStyle, innerStyle) + '"' + attrs + '/>').appendTo(container);
						}
					}
				}
			}
			if (a.objProp.type == 2 && style['height'] == 'auto') {
				a.dom.css('height', 'auto')
				a.input.on('change', function(e) {
					a.input.css('height', '2em');
					a.input.css({
						height: a.input[0].scrollHeight + "px"
					})
				}).css({
					'minHeight': '2em'
				})
			}
			if (a.custProp.actbtn || a.objProp.type == 3) {
				var editable = true, cs;
				if (! a.custProp.actbtn) {
					cs = [function(){
						a.input.data('value', '');
						a.input.val('').focus();
					}, '[b]mixcloud']
				} else
					cs = a.custProp.actbtn.split(',');
				if (cs.length < 2)
					cs[1] = 'question-circle';
				else {
					cs[1] = cs[1].trim();
					if (cs.length > 2)
						editable = (parseInt(cs[2].trim()) !== 0 ? false : true)
				}
				var actBtn = $('<i class="ibtn ' + $F.fas(cs[1]) + '"></i>').appendTo(fakeBox).click(function(e) {
					e.preventDefault();
					if (a.input.prop('disabled') || a.input.prop('readonly')) {
						if (! a.alwaysActive)
							return;
					}
					if ($.isFunction(cs[0])) {
						cs[0].call(a);
					} else
						a.instance.doCmd('P' + cs[0], {CTRL: a, INPUT: a.input}, runtime, a.id);
				})
				if (! editable) {
					a.input.prop('readonly', true);
					a.alwaysActive = true;
					a.input.bind('click', function(e) {
						e.preventDefault();
						e.stopPropagation();
						actBtn.trigger('click');
					});
					a.input.bind('keydown', function(e) {
						e.preventDefault();
						e.stopPropagation();
						if (e.keyCode == 46 || e.keyCode == 8)
							a.input.val('').trigger('change');
						else
							actBtn.trigger('click');
					})
				}
			}
			if (a.objProp.type == 3) {
				// 联想输入
				// 绘制控件时，对SQL条件引用的XITEM列值进行绑定
				var xitemBinder = {};
				$F.ognl(a.objProp.f || '' , function(propertyName) {
					if (propertyName.startWith('@')) {
						// 引用XITEM中其他列值
						var x = parseInt(propertyName.substring(1));
						a.xitemListener = a.xitemListener || {};
						a.xitemListener[x] = function(e) {
							xitemBinder[x] = e;
						}
					}
				})
				var filter = function() {
					return $F.ognl(a.objProp.f || '' , function(propertyName) {
						if (propertyName.startWith('@')) {
							var x = parseInt(propertyName.substring(1)), v = xitemBinder[x];
							if (v === undefined)
								return a.xitemData[x-1];
							else
								return v;
						} else
							return a.instance.getValue(propertyName, a.runtime);
					})
				}
				a.input.autocomplete({
					classes: {
					    "ui-autocomplete": "highlight"
					},
					create: function( event, ui ) {
						if (a.custProp.aclen >= 99) {
							a.input.on('keydown', function(e) {
								if (e.keyCode == 13) {
									a.input.autocomplete("instance")._search(a.input.val())
								}
							})
						}
					},
					source : function(request, response) {
						if (a.custProp.accmd) {
							//request.term.length = request.term.length - 1;
							// console.log(request.term)
							var ac = {
									FIND: request.term,
									RESULT: []
								};
							a.instance.doCmd('P' + a.custProp.accmd, {
								AC: ac
							}, a.runtime, a.id);
							var ar = [];
							$.each(ac.RESULT, function(i, v){
								if ($.type(v) == 'string')
									ar.push({label:v, category:v});
								else
									ar.push({
										label: v.key,
										category: v.value
									})
							})
							response(ar);
						} else {
							var params, find = (a.objProp.bfind? '%' : '') + request.term + '%';
							if (Verify.isDigit(request.term)) {
								// 数字联想
								params = [a.objProp.show, a.objProp.value, a.objProp.name, filter(), a.objProp.num || a.objProp.des, find]
								//console.log('数字联想: ' + $F.display(params));
							} else if (Verify.isAlphabetic(request.term)) {
								// 字母联想
								params = [a.objProp.show, a.objProp.value, a.objProp.name, filter(), a.objProp.chr || a.objProp.des, find]
								//console.log('字母联想: ' + $F.display(params));
							} else {
								// 普通联想
								params = [a.objProp.show, a.objProp.value, a.objProp.name, filter(), a.objProp.des, find]
								//console.log('普通联想: ' + $F.display(params));
							}
							a.input.data('value', '');
							$F.dataService('SystemDo2', {
								data: $F.sqlbean('DynBD.Select.LXFind', runtime.project.token, params, 10),
								digest: runtime.project.digest,
								success: function(data) {
									if (data.code < 1)
										return $F.err('Ctls - ctText', '联想失败: ' + data.message);
									// console.log(data);
									if (data.value[0].count == -1) {
										$F.err('Ctls - ctText', '联想失败: ' + data.value[0].key);
									} else {
										var ar = [];
										$.each(data.value[0].fields, function(i, v){
											ar.push({
												label:v[0],
												category:v[1]
											});
										})
										response(ar);
									}
								}
							});
						}
					},
					minLength : (a.custProp.aclen || 2),
					select : function(event, ui) {
						if (ui.item) {
							a.val(ui.item.label);
							a.input.data('value', ui.item.category);
							a.input.trigger('change');
						}
					}
				});
			}
			if (style['color'])
				a.input.css({color: style['color']});

			if (a.objProp.max > 0) {
				a.input.attr('max-length', a.objProp.max);
				a.input.on('input', function(e) {
					setTimeout(function(){
						//console.log(a.input.val().length);
						var v = a.input.val();
						v = v.subCn(a.objProp.max, a.instance.project.params['CHNLEN']);
						if (v != a.input.val())
							a.input.val(v);
					}, 0)
				})
			}
		} else if (a.objProp.type == 4) {
			// 投票器
			a.dom = $('<div data-type="' + a.type + '" class="' + clazz.join(' ') + '" style="' + getStyles(style, outerStyle) + '" />').appendTo(container);
			if (profile.lWidth > 0) {
				// 带标签控件
				a.dom.addClass('wl');
				var fakeBox = (a.dom.css('display') == 'flex') ? a.dom : ($('<div class="wl" />').appendTo(a.dom));
				a.lb = $('<span class="dyn_as dyn_label" style="width:' + profile.lWidth + 'px; line-height:' + style['height'] + '"/>').text(profile.lD).appendTo(fakeBox);
				a.voter = $('<span class="wlc dyn_voter" style="position:relative" />').appendTo(fakeBox);
			} else {
				a.voter = $('<span class="dyn_voter" style="' + getStyles(innerStyle) + ';position:relative" />').appendTo(a.dom);
			}
			var height = style['height'];
			if (!height || height == 'auto') {
				height = '2em';
			}
			a.stars = $('<span class="rating" style="line-height: ' + height + '"/>').appendTo(a.voter);
			a.objProp.max = a.objProp.max || 5;
			for(var i=a.objProp.max; i>0; i--) {
				$('<i class="star far fa-star" style="' + (i>1 ? 'margin-right:3px':'') + '" data-ref="' + i + '" />').appendTo(a.stars).on('click', function(e){
					var n = parseInt($(e.target).attr('data-ref')),
						list = $('i.star', a.stars).removeClass('selected'),
						item;
					for(var k=0; k<a.objProp.max; k++) {
						item = $(list[k]);
						if (parseInt(item.attr('data-ref')) <= n)
							item.addClass('selected');
					}
					a.input.val(n).trigger('change');
				});
			}
			a.input = $('<input type="text" style="display:none" placeholder="' + a.objProp.h + '" />').appendTo(a.dom);
		} else if (a.objProp.type == 5) {
			// 颜色选择器
			a.dom = $('<div data-type="' + a.type + '" class="' + clazz.join(' ') + '" style="' + getStyles(style, outerStyle) + '" />').appendTo(container);
			if (profile.lWidth > 0) {
				// 带标签控件
				a.dom.addClass('wl');
				var fakeBox = (a.dom.css('display') == 'flex') ? a.dom : ($('<div class="wl" />').appendTo(a.dom));
				a.lb = $('<span class="dyn_as dyn_label" style="width:' + profile.lWidth + 'px; line-height:' + style['height'] + '"/>').text(profile.lD).appendTo(fakeBox);
				a.form = $('<div class="wlc dyn_input_form" />').appendTo(fakeBox);
			} else {
				a.form = $('<div class="dyn_input_form" />').appendTo(a.dom);
			}
			a.input = $('<input type="text" style="' + getStyles(innerStyle) + '" />').appendTo(a.form);
			$('<a href="#" class="ibtn wb"><i class="far fa-times-ciecle"></i></a>').appendTo(a.form).click(function(e) {
				e.preventDefault();
				if (a.input.prop('disabled') || a.input.prop('readonly'))
					return;
				a.input.css('background', '#FFFFFF');
				a.input.val('').trigger('change');
			})
			H5Utils.colorPicker(a.input);
		} else if (a.objProp.type == 6) {
			// 富文本编辑
			a.dom = $('<div data-type="' + a.type + '" data-path="' + a.path + '" class="' + clazz.join(' ') + '" style="' + getStyles(style, outerStyle) + '" />').appendTo(container);
			if (profile.lWidth > 0) {
				// 带标签控件
				a.dom.addClass('wl');
				var fakeBox = (a.dom.css('display') == 'flex') ? a.dom : ($('<div class="wl" />').appendTo(a.dom));
				a.lb = $('<span class="dyn_as dyn_label" style="width:' + profile.lWidth + 'px; line-height:' + style['height'] + '"/>').text(profile.lD).appendTo(fakeBox);
				a.input = $('<textarea class="wlc" style="' + getStyles(innerStyle) + ';width:100%;height:100%" placeholder="' + (a.objProp.h || '') + '" />').appendTo(fakeBox);
			} else
				a.input = $('<textarea style="' + getStyles(innerStyle) + ';width:100%;height:100%" placeholder="' + (a.objProp.h || '') + '" />').appendTo(a.dom);
			var bid = $F.busyShow($F.lang('sys.ckeditorload'));
			H5Utils.initCkEditor(function(){
				a.createRicheditor(function(){
		        	$F.busyHide(bid);
				});
			})
		} else
			$F.alert('Invalid text type:' + a.objProp.type);

		if (a.custProp.entercmd) {
			a.input.on('keydown', function(e) {
				if (e.keyCode == 13) {
					a.instance.doCmd('P' + a.custProp.entercmd, {
						EVENT: {
							VALUE: a.input.val()
						}
					}, a.runtime, a.id)
					e.stopPropagation();
				}
			})
		}

		if (a.custProp.s_state)
			a.state(a.custProp.s_state);
		makeValueAndState(a, data, rowNum);
		return a;
	};

	ctlText.prototype = {
		state : function(e) {
			if (e == undefined) {
				return this._state;
			} else {
				this._state = e;
				if (e == 1)
					this.dom.hide();
				else {
					this.dom.show();
					this.disable(e == 2);
					this.input.prop('readonly', (e == 3));
					if (this.form)
						this.form.toggleClass('readonly', e == 3);
				}
			}
		},
		disable: function(e, byParent) {
			var a = this;
			if (byParent) {
				if (a.form)
					a.form.toggleClass('disabled', e || a.disabled);
				a.input.prop('disabled', e || a.disabled);
				if (a.objProp.type == 4) {
					a.voter.toggleClass('disabled', e || a.disabled);
				}
				a.parentDisabled = e;
			} else {
				if (a.form)
					a.form.toggleClass('disabled', e || a.parentDisabled);
				a.input.prop('disabled', e || a.parentDisabled);
				if (a.objProp.type == 4) {
					a.voter.toggleClass('disabled', e || a.parentDisabled);
				}
				this.disabled = e;
			}
		},

		val : function(t) {
			var a = this, objProp = a.profile.ot || {}, custProp = a.profile.o2 || {}, max = objProp.max;
			if (t == undefined) {
				if (objProp.type == 4)
					return a.input.val();
				if (objProp.type == 3) {
					var v = a.input.data('value');
					if (! v) {
						//a.input.val('');
						return '';
					}
					if (a.input.val() === '') {
						a.input.data('value', '');
						return '';
					}
					return v;
				} else {
					var v = a.input.val();
					v = v.subCn(max, a.instance.project.params['CHNLEN']);
					if (v != a.input.val())
						a.input.val(v);
					return a.instance.getValueByPropertyName(a.runtime, a.profile.vV, v.toString());
				}
			} else {
				if (a.custProp.mask) {
					var mask = a.custProp.maskstr;
					if (mask)
						a.input.val($F.shieldMask(t, mask));
					else
						a.input.val(a.instance.project.shieldString(t))
				} else {
					a.input.val(t);
				}
				if (objProp.type == 4) {
					// 投票器
					$('i.star:eq(' + (max - parseInt(t)) + ')', a.stars).trigger('click');
				} else if (objProp.type == 5) {
					H5Utils.colorPicker(a.input);
				} else if (objProp.type == 2) {
					// 对于包含autoheight的风格名的多行输入框，自动高度
					if (a.custProp.s_height == 'auto') {
						a.input.css('height', '2em');
						a.input.css({
							height: a.input[0].scrollHeight + "px"
						})
					}
				} else if (objProp.type == 6) {
					// 富文本
					if (a.ckeditor) {
						setTimeout(function(){
							a.ckeditor.resetDirty();
							a.ckeditor.setData(t);
						},10)
					}
				} else if (objProp.type == 3) {
					a.input.data('value', t);
					a.input.data('label', t);
				}
				return this;
			}
		},

		evt : function(e) {
			if (e == undefined)
				return {
					type: 0,
					data: this.val()
				}
			else
				this.val(e.data);
		},

		bind : function(e, callback) {
			this.input.bind(e, callback);
		},

		triggerChange : function(e) {
			this.input.trigger('change');
		},

		focus : function() {
			this.input.focus();
		},

		driftLayer : function(layer) {
			var owner = this.input;
			layer.drift(owner.offset().top, owner.offset().left, owner.offset().top + owner.outerHeight(), owner.offset().left + owner.outerWidth());
		},

		setStyle : function(cssStyle) {
			this.input.css(cssStyle);
		},

		commit : function() {
			if (this.objProp.type == 6) {
				// console.log(this.ckeditor);
				this.input.val(this.ckeditor.getData()).trigger('change');
			}
			return this;
		},

		label : function(e) {
			if (e == undefined)
				return (this.lb ? this.lb.text() : '');
			else {
				this.lb && this.lb.text(e);
				return this;
			}
		},

		createRicheditor : function(callback) {
			var a = this;
			var fup = a.custProp.fup || '/fs/uploadFile',
				iup = a.custProp.iup || '/fs/uploadImg',
				pup = a.custProp.pup || '/fs/uploadPDImg',
				cup = a.custProp.cup || '/fs/uploadCapture';

			var getUrl = function(url) {
				var u = a.instance.ognl(url, a.runtime);
				if (/^(http)/gi.test(u))
					return u;
				return $E.url + u;
			}
			CKEDITOR.config.filebrowserUploadUrl = getUrl(fup);
			CKEDITOR.config.filebrowserImageUploadUrl = getUrl(iup);
			CKEDITOR.config.imageUploadUrl = getUrl(pup);
			CKEDITOR.config.captureUploadUrl = getUrl(cup);
			var config = 'config.js?v=' + $E.ver;
			if (a.custProp.wy == 1)
				config = 'config_stand.js?v=' + $E.ver;
			else if (a.custProp.wy == 2)
				config = 'config_full.js?v=' + $E.ver;
			else if (a.custProp.wy == 3)
				config = 'config_simple.js?v=' + $E.ver;
			a.ckeditor = CKEDITOR.replace(a.input[0], {
				customConfig: config,
			    on: {
			        instanceReady: function( ev ) {
			        	this.container.addClass('elite');
			        	this.container.$.tabIndex = 0;
			        	this.on('blur', function(){
			        		this.container.removeClass('focus');
			        		if(this.checkDirty()) {
								a.input.val(this.getData()).trigger('change')
			        		}
			        	});
			        	this.on('focus', function(){
			        		this.container.addClass('focus');
			        	})
			        	a.input.data('ckeditor', a).forceClass('dyn_ckeditorInput')
		        		this.setData(a.input.val());
			        	if ($.isFunction(callback))
			        		callback();
			        }
			    }
			})
		},

		redraw : function() {
			var a = this;
			if (a.objProp.type == 6) {
				// console.log(this.ckeditor);
				if (a.ckeditor) {
					a.ckeditor.destroy();
					a.createRicheditor();
				}
			}
		},
		getItem: function(e) {
			return this.attributes[e];
		},
		setItem: function(e, v) {
			this.attributes[e] = v;
			return this;
		}
	};

	/*
	 * 动态页面组件：Datetime
	 */
	var cDatetime = function(container, profile, runtime, data, rowNum) {
		return new ctlDatetime(container, profile, runtime, data, rowNum);
	},

	ctlDatetime = function(container, profile, runtime, data, rowNum) {
		var a = this;
		a.id = profile.cId + (rowNum == undefined? '' : ('-' + rowNum));
		a.type = "DATETIME";
		a.disabled = false;
		a.instance = runtime.instance;
		a.container = container;
		a.runtime = runtime;
		a.path = runtime.namespace + '.' + a.id;
		a.profile = profile;
		a.objProp = profile.ot || {};
		a.custProp = profile.o2 || {};
		a.xitemData = data;
		a.xitemRow = rowNum;
		a.parentDisabled = a.disabled = false;
		a.attributes = {};
		// console.log(a);
		// alert(JSON.stringify(runtime.data.local['var']))

		var q = ctlStyle(a), style = q.style, outerStyle = q.outerStyle, innerStyle = q.innerStyle, clazz = q.clazz, attrs = '';
		if (a.objProp.ri)
			clazz.push('dyn_rtl');
		innerStyle['font-size'] = 'inherit';
		if (a.custProp.required)
			attrs += ' required="required"'

		// 日期选择器
		a.mask = a.objProp.t.trim() || 'Y-m-d H:i';
		if ($E.device == 'mobile') {
			var type = 'datetime';
			if (a.mask.length < 6)
				type = a.mask.startWith('Y') ? 'date' : 'time';
			if (profile.lWidth > 0) {
				// 带标签控件
				clazz.push('wl');
				a.dom = $('<div data-type="' + a.type + '" data-path="' + a.path + '" class="' + clazz.join(' ') + '" style="' + getStyles(style, outerStyle) + '" />').appendTo(container);
				var fakeBox = (a.dom.css('display') == 'flex') ? a.dom : ($('<div class="wl" />').appendTo(a.dom));
				a.lb = $('<span class="dyn_as dyn_label" style="width:' + profile.lWidth + 'px; line-height:' + style['height'] + '"/>').text(profile.lD).appendTo(fakeBox);
				a.input = $('<input type="text" class="wlc" style="' + getStyles(innerStyle) + '"' + attrs + '/>').appendTo(fakeBox);
			} else {
				a.dom = a.input = $('<input type="' + type + '" data-type="' + a.type + '" data-id="' + a.id + '" class="' + clazz.join(' ') + '" style="' + getStyles(style, outerStyle, innerStyle) + '"' + attrs + '/>').appendTo(container);
			}

			a.options = {
				preset: type,
				stepMinute: 1,
				mode: 'scroller',
				theme: 'ios',
				display: 'bottom',
				timeWheels: (a.mask.indexOf('H:i:s') !== -1 ? 'HHiiss' : 'HHii'),
	            timeFormat: (a.mask.indexOf('H:i:s') !== -1 ? 'HH:ii:ss' : 'HH:ii'),
	            lang: 'zh_CN',
	            setText: '设置',
	            cancelText: '取消',
	            disabled: true
			}
			// console.log(a.options)
			a.input.mobiscroll(a.options);
		} else {
			var datepickerVisible = a.mask.startWith('Y') || a.mask.startWith('m') || a.mask.startWith('d');
			var timepickerVisible = a.mask.endWith('s') || a.mask.endWith('i') || a.mask.endWith('H');

			a.dom = $('<div data-type="' + a.type + '" data-path="' + a.path + '" class="' + clazz.join(' ') + '" style="' + getStyles(style, outerStyle) + '" />').appendTo(container);
			if (profile.lWidth > 0) {
				// 带标签控件
				a.dom.addClass('wl');
				var fakeBox = (a.dom.css('display') == 'flex') ? a.dom : ($('<div class="wl" />').appendTo(a.dom));
				a.lb = $('<span class="dyn_as dyn_label" style="width:' + profile.lWidth + 'px; line-height:' + style['height'] + '"/>').text(profile.lD).appendTo(fakeBox);
				a.form = $('<div class="wlc dyn_input_form" />').appendTo(fakeBox);
			} else {
				a.form = $('<div class="dyn_input_form" />').appendTo(a.dom);
			}
			a.input = $('<input type="text" style="' + getStyles(innerStyle) + '"' + attrs + '/>')
				.appendTo(a.form)
				.data('shell', a.form)
				.bind('blur', function(e) {
					if (a.input.val() != a.value)
						a.input.trigger('change');
				})
			$('<i class="ibtn far fa-calendar-alt"></i>').appendTo(a.form).click(function(e) {
				e.preventDefault();
				if (a.input.prop('disabled') || a.input.prop('readonly'))
					return;
				a.input.datetimepicker({
					zIndex : 100002,
					fixed: true,
					showOnFocus: false,
				    format: a.mask,
				    exactTime: true,
				    datepicker: datepickerVisible,
				    timepicker: timepickerVisible,
					locale: $E.lang
				});
				$.datetimepicker.setLocale($E.lang)
			})
		}

		if (profile.vV)
			a.dom.attr('data-property', profile.vV);
		a.value = '';
		if (a.custProp.s_state)
			a.state(a.custProp.s_state);
		makeValueAndState(a, data, rowNum);
		return a;

	};

	ctlDatetime.prototype = {
		state : function(e) {
			if (e == undefined)
				return this._state;
			else {
				this._state = e;
				if (e == 1)
					this.dom.hide();
				else {
					this.dom.show();
					this.input.prop('readonly', (e == 3));
					if (this.form)
						this.form.toggleClass('readonly', e == 3);
					this.disable(e == 2);
				}
			}
		},
		disable: function(e, byParent) {
			var a = this;
			if (byParent) {
				if (a.form)
					a.form.toggleClass('disabled', e || a.disabled);
				a.input.prop('disabled', e || a.disabled);
				if ($E.device == 'mobile') {
					a.options.disabled = (e || a.disabled || a._state == 3);
					a.input.mobiscroll('destroy').mobiscroll(a.options);
				}
				a.parentDisabled = e;
			} else {
				if (a.form)
					a.form.toggleClass('disabled', e || a.parentDisabled);
				a.input.prop('disabled', e);
				if ($E.device == 'mobile') {
					a.options.disabled = (e || a._state == 3);
					a.input.mobiscroll('destroy').mobiscroll(a.options);
				}
				a.disabled = e;
			}
		},

		val : function(t) {
			var a = this;
			if (t == undefined)
				return a.value = a.input.val();
			else {
				if (t == null)
					return this;

				// alert('date:' + t);
				if (t != this.value) {
					a.value = t;
					try {
						if (t == '')
							a.input.val('');
						else if (t.startWith == '1900') {
							t = '';
							a.instance.fireValue(a.profile.vV, a.runtime, {
								type: 0,
								data: ''
							}, a);
							a.input.val('');
						} else {
							//var date = Date.parseDate(t, Date.patterns.ISO8601LongPattern);
							var date = $F.parseDate(t);
							if (date.getFullYear() == 1900) {
								a.instance.fireValue(a.profile.vV, a.runtime, {
									type: 0,
									data: ''
								}, a);
								a.input.val('');
							} else {
								a.input.val(date.format2(a.mask));
							}
						}
					} catch(e) {
						$F.err('Ctls - Datetime', '不合法的日期格式：' + t);
						console.error(e);
					}
					// console.info(a.input.val())
					if ($E.device == 'mobile') {
						a.input.mobiscroll('destroy').mobiscroll(a.options);
					} else
						a.input.datetimepicker('refresh');
				}
				return this;
			}
		},

		evt : function(e) {
			if (e == undefined)
				return {
					type: 0,
					data: this.val()
				}
			else
				this.val(e.data);
		},

		bind : function(e, callback) {
			this.input.bind(e, callback);
		},

		triggerChange : function(e) {
			this.input.trigger('change');
		},

		focus : function() {
			this.input.focus();
		},

		label : function(e) {
			if (e == undefined)
				return (this.lb ? this.lb.text() : '');
			else {
				this.lb && this.lb.text(e);
				return this;
			}
		},
		getItem: function(e) {
			return this.attributes[e];
		},
		setItem: function(e, v) {
			this.attributes[e] = v;
			return this;
		}
	};

	/*
	 * 动态页面组件：Calendar
	 */
	var cCalendar = function(container, profile, runtime, data, rowNum) {
		return new ctlCalendar(container, profile, runtime, data, rowNum);
	},

	ctlCalendar = function(container, profile, runtime, data, rowNum) {
		var a = this;
		a.id = profile.cId + (rowNum == undefined? '' : ('-' + rowNum));
		a.type = "CALENDAR";
		a.disabled = false;
		a.instance = runtime.instance;
		a.container = container;
		a.runtime = runtime;
		a.path = runtime.namespace + '.' + a.id;
		a.profile = profile;
		a.objProp = profile.ot || {};
		a.custProp = profile.o2 || {};
		a.xitemData = data;
		a.xitemRow = rowNum;
		a.dblclickCalls = [];
		a.parentDisabled = a.disabled = false;
		a.attributes = {};
		//console.log(a);

		var q = ctlStyle(a), style = q.style, outerStyle = q.outerStyle, innerStyle = q.innerStyle, clazz = q.clazz;
		if (a.objProp.ri)
			clazz.push('dyn_rtl');
		innerStyle['font-size'] = 'inherit';

		a.mask = 'Y-m-d';
		if ($E.device == 'mobile') {
			// 用于手机的日历
			style['top'] = style['left'] = style['right'] = style['bottom'] = style['height'] =undefined;
			style['position'] = 'relative';
			style['width'] = '100%';
			style['overflow'] = 'hidden';
			a.dom = $('<div data-type="' + a.type + '" data-path="' + a.path + '" class="' + clazz.join(' ') + ' unselectable" style="' + getStyles(style, outerStyle) + '" />').appendTo(container);

			var build = '<ul class="mobile-calendar">';
			var days = ['日','一','二','三','四','五','六'];
			for(var i=0; i<days.length; i++) {
				build += '<li class="cal ' + (i==0?'sunday':'') + '"><span class="a"><span class="day">' + days[i] + '</span><span class="date" /></span></li>'
			}
			build += '<li class="title"><span class="month"></span><a href="#" class="today">今</a></ul>';
			a.dom.append(build);
			a.masker = $('<div class="eliteDisabledMasker" />').appendTo(a.dom);
			a.input = $('<input type="text" style="display:none" />').appendTo(a.dom);

			$('li.cal .a', a.dom).on('click', function(e) {
				var dateSpan = $('span.date', $(e.currentTarget)), date = dateSpan.data('date');
				$F.process(function() {
					a.input.val(date).trigger('change');
				})
				$('span.date', a.dom).removeClass('current');
				dateSpan.addClass('current');
				a.currentDate = $F.parseDate(date);
			})
			$('a.today', a.dom).on('click', function(e) {
				e.preventDefault();
				a.firstDate = getFirstDay(new Date());
				drawMobileCalendar(a);
			})
			a.touchPos = a.moveUnit = 0;
			a.dom.on('touchstart', function(e) {
				a.touchPos = e.originalEvent.targetTouches[0].pageX;
				a.moveUnit = a.dom.width() / 7;
				//console.log('Cell width: ' + a.moveUnit);
			})
			a.dom.on('touchmove', function(e) {
				var touchMove = e.originalEvent.targetTouches[0].pageX - a.touchPos;
				var mv = Math.round(touchMove / a.moveUnit);
				//console.log('Move unit: ' + mv);
				if (mv !== 0) {
					a.touchPos = e.originalEvent.targetTouches[0].pageX;
					a.firstDate = new Date(a.firstDate.getTime() - mv * 86400000 );
					// console.log(a.firstDate.format('yyyy-MM-dd hh:mm:ss'));
					drawMobileCalendar(a);
				}
			})
			if (! a.profile.vV)
				a.val('');
		} else {
			// 用于PC的日历
			a.dom = $('<div data-type="' + a.type + '" data-path="' + a.path + '" class="' + clazz.join(' ') + '" style="' + getStyles(style, outerStyle) + ';overflow:visible" />').appendTo(container);
			a.input = $('<input type="text" style="display:none" />').appendTo(a.dom);
			if (parseInt(a.dom.css('flex-grow'))) {
				// 用于处理弹性布局
				if (a.dom.parent().css('flex-direction') == 'column')
					a.dom.css('height', 'auto');
				else
					a.dom.css('width', 'auto');
				a.box = $('<div class="wrapper" style="overflow:auto" />').appendTo(a.dom);
			} else {
				a.box = $('<div style="width:100%;height:100%" />').appendTo(a.dom);
			}
			a.calendar = a.box.wisCalendar({
				formatDate: a.mask,
				customData: true,
				onSelected : function(date, dom) {
					a.cellDom = dom;
					a.input.val(date.dateFormat(a.mask)).trigger('change');
				},
				onDblClick : function(date, e) {
					$.each(a.dblclickCalls, function() {
						this(e, {
							DATE: date
						});
					})
				},
				onRange : function(startDate, endDate, curDate, calendar) {
					if (a.custProp.rangecmd) {
						a.instance.doCmd('P' + a.custProp.rangecmd, {
							EVENT: {
								START: startDate.dateFormat(a.mask),
								END: endDate.dateFormat(a.mask),
								CUR: curDate
							}
						}, a.runtime, a.id)
					}
				},
				onAddnew : function(data, callback) {
					if (a.custProp.newcmd) {
						a.instance.doCmd('P' + a.custProp.newcmd, {
							EVENT: {
								DATA: data,
								callback: callback
							}
						}, a.runtime, a.id)
					} else
						callback(data);
				},
				onEdit : function(data, callback) {
					if (a.custProp.editcmd) {
						a.instance.doCmd('P' + a.custProp.editcmd, {
							EVENT: {
								DATA: data,
								callback: callback
							}
						}, a.runtime, a.id)
					} else
						callback(data);
				},
				onRemove : function(data, callback) {
					if (a.custProp.delcmd) {
						a.instance.doCmd('P' + a.custProp.delcmd, {
							EVENT: {
								DATA: data,
								callback: callback
							}
						}, a.runtime, a.id)
					} else
						callback(data);
				},
				onEvent: function(event, eventDom) {
					return;
				}
			});
			a.masker = $('<div class="eliteDisabledMasker" />').appendTo(a.dom);

			if (a.custProp.events) {
				// 对事件变量进行监听，变量格式要求第一列为日期字符串，第二列为事件
				a.instance.bindValue(a.custProp.events, a, function(e) {
					a.calendar.markEvents(e.data);
				});
			}
			if (a.custProp.notifies) {
				// 对假日变量进行监听，变量格式要求第一列为日期字符串，第二列为假日名称
				a.instance.bindValue(a.custProp.notifies, a, function(e) {
					a.calendar.markVacations(e.data);
				});
			}
			if (a.custProp.vacations) {
				// 对假日变量进行监听，变量格式要求第一列为日期字符串，第二列为假日名称
				a.instance.bindValue(a.custProp.vacations, a, function(e) {
					a.calendar.markVacations(e.data);
				});
			}
		}
		if (a.custProp.s_state)
			a.state(a.custProp.s_state);
		makeValueAndState(a, data, rowNum);
		return a;
	};

	var getFirstDay = function(t) {
		var v = new Date();
		v.setDate(t.getDate() - t.getDay() + 1);
		return v;
	},

	drawMobileCalendar = function(fn) {
		var pointer = new Date(fn.firstDate.getTime()),
			today = new Date().format('yyyy-MM-dd'),
			currentDay = fn.currentDate.format('yyyy-MM-dd'),
			fmt;
		$('span.date', fn.dom).each(function(i, link) {
			link = $(link).data('date', pointer.format('yyyy-MM-dd')).empty().removeClass('current').removeClass('today');
			link.append('<span class="lb">' + pointer.getDate() + '</span>');
			fmt = pointer.format('yyyy-MM-dd');
			if (fmt == today)
				link.addClass('today');
			if (fmt == currentDay)
				link.addClass('current')
			if (i == 6)
				$('span.month', fn.dom).text((pointer.getMonth() + 1) + '月')
			pointer.setDate(pointer.getDate() + 1);
		})
	};

	ctlCalendar.prototype = {
		state : function(e) {
			if (e == undefined)
				return this._state;
			else {
				this._state = e;
				if (e == 1)
					this.dom.hide();
				else {
					this.dom.show();
					this.disable(e == 2);
				}
			}
		},
		disable: function(e, byParent) {
			if (byParent) {
				if (e || this.disabled)
					this.masker.show();
				else
					this.masker.hide();
				this.parentDisabled = e;
			} else {
				this.masker.toggle(e || this.parentDisabled);
				this.disabled = e;
			}
		},

		val : function(t) {
			var a = this;
			if (t == undefined)
				return a.input.val();
			else {
				if (t == null)
					return this;

				try {
					if (t == '')
						a.input.val('');
					else if (t.startWith == '1900') {
						t = '';
						a.instance.fireValue(a.profile.vV, a.runtime, {
							type: 0,
							data: ''
						}, a);
						a.input.val('');
					} else {
						//var date = Date.parseDate(t, Date.patterns.ISO8601LongPattern);
						a.input.val($F.parseDate(t).dateFormat(a.mask));
					}
					if ($E.device == 'mobile') {
						a.currentDate = $F.parseDate(t);
						a.firstDate = getFirstDay(a.currentDate);
						drawMobileCalendar(a);
					} else {
						a.calendar.current(a.input.val());
					}
				} catch(e) {
					$F.err('Ctls - Calendar', e);
					console.error(e);
				}
				return this;
			}
		},

		evt : function(e) {
			if (e == undefined)
				return {
					type: 0,
					data: this.val()
				}
			else
				this.val(e.data);
		},

		bind : function(e, callback) {
			if (e == 'dblclick')
				this.dblclickCalls.push(callback);
			else if (e == 'change')
				this.input.bind(e, callback);
		},

		triggerChange : function(e) {
			this.input.trigger('change');
		},

		driftLayer : function(layer) {
			if (! this.cellDom)
				return $F.err('Ctls - table', '当前没有选中的日期');
			var owner = this.cellDom;
			layer.drift(owner.offset().top, owner.offset().left, owner.offset().top + owner.outerHeight(), owner.offset().left + owner.outerWidth());
		},

		focus : function() {
			this.input.focus();
		},

		destroy : function() {
			if ($E.device == 'mobile') {
			} else {
				this.calendar.destroy();
			}
		},
		getItem: function(e) {
			return this.attributes[e];
		},
		setItem: function(e, v) {
			this.attributes[e] = v;
			return this;
		}
	};

	/*
	 * 动态页面组件：Label
	 */
	var cLabel = function(container, profile, runtime, data, rowNum) {
		return new ctlLabel(container, profile, runtime, data, rowNum);
	},

	ctlLabel = function(container, profile, runtime, data, rowNum) {
		var a = this;
		a.id = profile.cId + (rowNum == undefined? '' : ('-' + rowNum));
		a.type = "LABEL";
		a.disabled = false;
		a.instance = runtime.instance;
		a.container = container;
		a.runtime = runtime;
		a.path = runtime.namespace + '.' + a.id;
		a.profile = profile;
		a.objProp = profile.ot || {};
		a.custProp = profile.o2 || {};
		a.xitemRow = rowNum;
		a.xitemData = data;
		a.attributes = {};
		// console.log(a);

		let q = ctlStyle(a),
			style = q.style,
			outerStyle = q.outerStyle,
			innerStyle = q.innerStyle,
			clazz = q.clazz,
			as = a.custProp.wrap ? '' : 'dyn_as';

		a.dom = $('<div data-type="' + a.type + '" data-path="' + a.path + '" class="' + clazz.join(' ') + '" style="' + getStyles(style, outerStyle) + '" />').appendTo(container);
		if (a.custProp.marquee) {
			a.input = a.dom.addClass('dyn_marquee');
			a.marquee = $('<div class="flyerbox"/>').appendTo(a.dom).marquee();
		} else {
			if (profile.lWidth > 0) {
				if (profile.vV || data !== undefined) {
					// 有变量绑定
					a.fakebox = $('<div style="display:flex"/>').appendTo(a.dom);
					a.lb = $('<span class="dyn_as dyn_label" style="width:' + profile.lWidth + 'px;line-height:' + style['height'] + '"/>')
						.text(profile.lD)
						.appendTo(a.fakebox);
					if (a.custProp.align)
						a.lb.css('textAlign', a.custProp.align);
					a.input = $('<span class="' + as + '" style="' + getStyles(innerStyle) + ';flex:1;line-height:' + style['height'] + '"></span>').appendTo(a.fakebox);
				} else {
					// 没有变量绑定，仅做标签
					a.input = a.dom.addClass(a.objProp.ah? '' : as)
						.text(profile.lD)
						.css({
							'lineHeight': style['height'],
							'textAlign' : a.custProp.align || 'left'
						});
				}
			} else {
				a.input = a.dom.addClass(a.objProp.ah? '' : as)
					.css({
						'lineHeight': style['height'],
						'textAlign' : a.custProp.align || 'left'
					});
			}
		}

		if (a.custProp.s_state)
			a.state(a.custProp.s_state);
		makeValueAndState(a, data, rowNum);
		return a;
	};

	ctlLabel.prototype = {
		state : function(e) {
			if (e == undefined)
				return this._state;
			else {
				this._state = e;
				if (e == 1)
					this.dom.hide();
				else {
					this.dom.show();
				}
			}
		},
		disable: function(e, byParent) {
		},

		val : function(t) {
			var a = this, objProp = a.profile.ot || {};
			if (t == undefined)
				return a.value;

			if (t != a.value) {
				a.value = t;
				if (a.custProp.marquee) {
					// 跑马灯
					a.marquee.clear();
					//console.log(a.flyer)
					if (t instanceof Array) {
						if (t.length == 0) {
							// for test
							t.push('customization marquee board');
						}
						// console.log(a.flyer);
						$.each(t, function(i, v){
							a.marquee.addItem('<span class="item">' + v + '</span>');
						})
						if (a.dom.is(':visible')) {
							a.marquee.flyer.find('span.item').css('lineHeight', a.dom.height() + 'px')
						}
					} else
						$F.err('Ctls - Label', '跑马灯控件只接受表格变量')
				} else {
					if ($.type(t) == 'string') {
						t = $F.ognl(t.trim(), function(propertyName) {
							return a.instance.getValue(propertyName, a.runtime);
						})
					}

					var str = '';
					if (objProp.ft == 'D') {
						// 日期格式化
						if ($.type(t) == 'date') {
							str = t.format(objProp.f);
						} else {
							if ($.type(t) !== 'string')
								throw new Error('无效的日期对象：' + $.type(t));
							var format, st = t.split(' ');
							if (st.length < 2) {
								var subt = st[0].split(':');
								if (subt.length > 1) {
									// 字符串为时间
									if (subt.length == 2)
										format = "H:i";
									else
										format = "H:i:s";
								}  else {
									// 字符串为日期
									format = "Y-m-d";
								}
							} else {
								// 字符串为完整日期时间
								var subt = t.trim().split(':');
								if (subt.length > 1) {
									// 字符串为时间
									if (subt.length == 2)
										format = "Y-m-d H:i";
									else
										format = "Y-m-d H:i:s";
								}  else {
									// 字符串为日期
									format = "Y-m-d H";
								}
							}
							var date = Date.parseDate(t, format);
							if (date)
								str = date.format(objProp.f);
						}
					} else if (objProp.ft == 'N') {
						// 数字格式化
						str = $F.formatNumber(t, objProp.f);
					} else if (objProp.ft == 'C') {
						// 字符串格式化
						if (objProp.f.trim().toLowerCase() == 'mask')
							str = a.instance.project.shieldString(t);
						else {
							var mask = (/^MASK\((.*)\)/gi).exec(objProp.f.trim());
							if (mask) {
								if (! mask[1])
									str = a.instance.project.shieldString(t);
								else
									str = $F.shieldMask(t, mask[1]);
							} else
								str = $F.formatString(t, objProp.f);
						}
					} else {
						if ($.type(t) == 'string' && t.toUpperCase().startWith('<HTML>'))
							str = t.substring(6);
						else {
							str = t;
							if ($.type(str) !== 'string')
								str = str.toString();
							str = str.replaceAll('\n', '<br/>');
						}
					}

					if (a.profile.lD !== undefined && a.profile.lWidth <= 0) {
						// 有左标签部分，但是宽度为0，则使用自动拼接
						str = (a.profile.lD || '') + str;
					}
					//console.log('String: '  + str)

					if (a.custProp.format) {
						// 字符串拼接格式化
						str = a.custProp.format.format(str);
					}
					a.input.text(str);
					if (a.custProp.tips)
						a.input.attr('title', str)
				}
			}
			return this;
		},

		evt : function(e) {
			if (e == undefined)
				return {
					type: 0,
					data: this.val()
				}
			else
				this.val(e.data);
		},

		bind : function(e, callback) {
			this.input.bind(e, callback);
		},

		triggerChange : function(e) {
			this.input.trigger('click');
		},

		setStyle : function(cssStyle) {
			this.dom.css(cssStyle);
		},

		onHover : function(layerId) {
			var a = this, ctrl = a.runtime.ctls[layerId];
			if (! ctrl)
				return console.error('Layer not exist, id=' + layerId);
			a.input.hover(function(){
				a.driftLayer(ctrl);
			}, function(){
				$(document).click()
			})
		},

		driftLayer : function(layer) {
			var owner = this.dom;
			layer.drift(owner.offset().top, owner.offset().left, owner.offset().top + owner.outerHeight(), owner.offset().left + owner.outerWidth());
		},

		label : function(e) {
			if (e == undefined)
				return (this.lb ? this.lb.text() : '');
			else {
				this.lb && this.lb.text(e);
				return this;
			}
		},
		getItem: function(e) {
			return this.attributes[e];
		},
		setItem: function(e, v) {
			this.attributes[e] = v;
			return this;
		}
	};

	/*
	 * 动态页面组件：Image
	 */
	var cImage = function(container, profile, runtime, data, rowNum) {
		return new ctlImage(container, profile, runtime, data, rowNum);
	},

	ctlImage = function(container, profile, runtime, data, rowNum) {
		var a = this;
		a.id = profile.cId + (rowNum == undefined? '' : ('-' + rowNum));
		a.type = "IMAGE";
		a.disabled = false;
		a.instance = runtime.instance;
		a.container = container;
		a.runtime = runtime;
		a.path = runtime.namespace + '.' + a.id;
		a.profile = profile;
		a.objProp = profile.ot || {};
		a.custProp = profile.o2 || {};
		a.xitemRow = rowNum;
		a.xitemData = data;
		a.attributes = {};
		// console.log(a);

		var q = ctlStyle(a), style = q.style, outerStyle = q.outerStyle, innerStyle = q.innerStyle, clazz = q.clazz;
		if (! style['text-align'])
			style['text-align'] = 'center';
		if (! style['vertical-align'])
			style['vertical-align'] = 'middle';
		if (! style['overflow'])
			style['overflow'] = 'hidden';
		a.dom = $('<div data-type="' + a.type + '" data-path="' + a.path + '" class="' + clazz.join(' ') + '" style="' + getStyles(style, outerStyle) + '" />').appendTo(container);
		if (style['width'] == 'auto' || style['height'] == 'auto') {
			a.dom.css({
				'overflow' : 'hidden'
			})
			a.img = $('<img style="' + getStyles(innerStyle) + ';width:100%;height:100%" />').appendTo(a.dom);
		} else {
			a.img = $('<img style="' + getStyles(innerStyle) + '"/>').appendTo(a.dom);
		}
		if (a.custProp.viewer)
			a.dom.viewer();
		if (a.custProp.tooltip)
			a.img.attr('title', a.custProp.tooltip)

		/*
		 * objProp
		 * b: 是否有边框
		 * t: 0=按比例缩放，1=拉伸铺满，2=原图
		 */
		if (a.objProp.b) {
			a.dom.css({
				border: '1px solid #ccc'
			})
		}
		if (! a.objProp.t)
			// 原比例缩放
			a.img.css({
				'maxWidth': style.width,
				'maxHeight' : style.height
			});
		else if (a.objProp.t == 1)
			// 拉伸
			a.img.css({
				width: '100%',
				height: '100%'
			});
		else
			// 原图
			a.img.css({});

		if (a.custProp.resource) {
			// 使用本地文件资源
			a.val(a.custProp.resource);
		}

		if (a.custProp.s_state)
			a.state(a.custProp.s_state);
		makeValueAndState(a, data, rowNum);
		return a;
	};

	ctlImage.prototype = {
		state : function(e) {
			if (e == undefined)
				return this._state;
			else {
				this._state = e;
				if (e == 1)
					this.dom.hide();
				else
					this.dom.show();
			}
		},
		disable: function(e, byParent) {
		},

		val : function(t) {
			var a = this;
			if (t == undefined)
				return a.img[0].src;
			else {
				if (! t)
					a.img[0].src = $E.url + '/images/i.gif';
				else {
					if ($.type(t) == 'string') {
						t = $F.ognl(t, function(propertyName) {
							return a.instance.getValue(propertyName, a.runtime);
						})
					}
					if (t.toLowerCase().startWith('http'))
						a.img[0].src = t;
					else {
						if (t.toLowerCase().startWith('res:')) {
							a.img[0].src = $E.url + '/' + t.substring(4);
						} else if (t.startWith('data:')) {
							a.img[0].src = t;
						} else {
							if (t.startWith('/fs/'))
								a.img[0].src = $E.url + t;
							else if (t.startWith('fs/'))
								a.img[0].src = $E.url + '/' + t;
							else
								a.img[0].src = $E.url + '/fs/get?file=' + t;
						}
					}
				}
				return a;
			}
		},

		evt : function(e) {
			if (e == undefined)
				return {
					type: 0,
					data: this.val()
				}
			else
				this.val(e.data);
		},

		bind : function(e, callback) {
			this.img.bind(e, callback);
		},

		triggerChange : function(e) {
			this.img.trigger('click');
		},

		driftLayer : function(layer) {
			var owner = this.img;
			layer.drift(owner.offset().top, owner.offset().left, owner.offset().top + owner.outerHeight(), owner.offset().left + owner.outerWidth());
		},

		setStyle : function(cssStyle) {
			this.img.css(cssStyle);
		},

		onHover : function(layerId) {
			var a = this, ctrl = a.runtime.ctls[layerId];
			if (! ctrl)
				return console.error('Layer not exist, id=' + layerId);
			a.input.hover(function(){
				a.driftLayer(ctrl);
			}, function(){
				$(document).click()
			})
		},
		getItem: function(e) {
			return this.attributes[e];
		},
		setItem: function(e, v) {
			this.attributes[e] = v;
			return this;
		}

	};

	/*
	 * 动态页面组件：Link
	 */
	var cLink = function(container, profile, runtime, data, rowNum) {
		return new ctlLink(container, profile, runtime, data, rowNum);
	},

	ctlLink = function(container, profile, runtime, data, rowNum) {
		var a = this;
		a.id = profile.cId + (rowNum == undefined? '' : ('-' + rowNum));
		a.type = "LINK";
		a.disabled = false;
		a.instance = runtime.instance;
		a.container = container;
		a.runtime = runtime;
		a.path = (runtime.namespace ? (runtime.namespace + '.' + a.id) : a.id);
		a.profile = profile;
		a.objProp = profile.ot || {};
		a.custProp = profile.o2 || {};
		a.xitemRow = rowNum;
		a.xitemData = data;
		a.parentDisabled = a.disabled = false;
		a.attributes = {};
		//console.log(a);

		var q = ctlStyle(a), style = q.style, outerStyle = q.outerStyle, innerStyle = q.innerStyle, clazz = q.clazz;
		clazz.push('dyn_link');
		a.input = $('<a data-type="' + a.type + '" data-path="' + a.path + '" class="' + clazz.join(' ') + '" style="' + getStyles(style, outerStyle, innerStyle) + '" href="javascript:;">' + (profile.lD || '') + '</a>').appendTo(container);
		a.input.css('lineHeight', style['height'])
		if (a.objProp.tw)
			a.input.attr('target', a.objProp.tw);
		if (a.objProp.url) {
			if (a.objProp.url.toUpperCase().startWith('CMD#')) {
				var cmdId = a.objProp.url.substring(4);
				a.input.attr('href', '#').attr('data-cmd', cmdId);
				a.input.on('click', function(e) {
					e.preventDefault();
					if (a.custProp.stoppg)
						e.stopPropagation();
					if (a.input.hasClass('disabled'))
						return;
					a.instance.doCmd('P' + cmdId, {
						EVENT: {
							GRIDROW: a.xitemRow + 1,
							ROWDATA: a.xitemData,
						}
					}, a.runtime, a.id);
				})
			} else
				a.input.attr('href', a.objProp.url);
		} else {
			a.input.on('click', function(e) {
				if (a.custProp.stoppg || a.input.hasClass('disabled')) {
					e.preventDefault();
					e.stopPropagation();
				}
			})
		}
		if (a.custProp.tooltip)
			a.input.attr('title', a.custProp.tooltip);

		if (a.custProp.s_state)
			a.state(a.custProp.s_state);
		makeValueAndState(a, data, rowNum);

		if (a.custProp.lbver) {
			a.text(a.instance.getValue(a.custProp.lbver, runtime));
			a.instance.bindValue(a.custProp.lbver, a, function(e) {
				if (a.custProp.both)
					a.val(e);
				else
					a.text(e);
			});
		}

		return a;
	};

	ctlLink.prototype = {
		state : function(e) {
			if (e == undefined)
				return this._state;
			else {
				this._state = e;
				if (e == 1)
					this.input.hide();
				else {
					this.input.show();
					this.disable(e == 2);
				}
			}
		},
		disable : function(e, byParent) {
			if (byParent) {
				this.input.toggleClass('disabled', e || this.disabled);
				this.parentDisabled = e;
			} else {
				this.input.toggleClass('disabled', e || this.parentDisabled);
				this.disabled = e;
			}
		},

		val : function(t) {
			var a = this;
			if (t == undefined)
				return a.input.attr('href');
			else {
				if ($.type(t) == 'string') {
					t = $F.ognl(t, function(propertyName) {
						return a.instance.getValue(propertyName, a.runtime);
					})
				}
				a.input.attr('href', t);
				if (a.input.text() == '' || a.custProp.both)
					a.input.text(t);
				return this;
			}
		},
		evt : function(e) {
			if (e == undefined)
				return {
					type : 0,
					data : this.val()
				}
			else
				this.val(e.data);
		},

		bind : function(e, callback) {
			this.input.bind(e, callback);
		},

		triggerChange : function(e) {
			this.input.trigger('click');
		},

		focus : function() {
			this.input.focus();
		},

		driftLayer : function(layer) {
			var owner = this.input;
			layer.drift(owner.offset().top, owner.offset().left, owner.offset().top + owner.outerHeight(), owner.offset().left + owner.outerWidth());
		},

		toggle : function(e) {
			var a = this;
			a.toggleClass(a.profile.ot.ss, a.profile.ot.sv == e);
		},
		toggleClass : function(className, expression) {
			this.input.toggleClass(className, expression);
		},

		/**
		 * 全屏模式方法
		 * 在动态页面加载方法中调用命令
		 * H5Utils.fullscreenTriger(ctlId)
		 * ctlId : 注册全屏模式的按钮或者链接控件
		 * 全屏的对象为该按钮或者控件的父容器
		 */
		fullscreenTriger : function() {
			var a = this;
			a.input.on('click', function(e) {
				H5Utils.fullscreen(a.container);
			})
		},

		setStyle : function(cssStyle) {
			this.input.css(cssStyle);
		},

		onHover : function(layerId) {
			var a = this, ctrl = a.runtime.ctls[layerId];
			if (! ctrl)
				return console.error('Layer not exist, id=' + layerId);
			a.input.hover(function(){
				a.driftLayer(ctrl);
			}, function(){
				$(document).click()
			})
		},

		html : function(t) {
			if (t == undefined)
				return this.input.html();
			else {
				this.input.html(t);
				return this;
			}
		},

		text : function(e) {
			if (e == undefined)
				return this.profile.lD || this.input.text();
			else {
				this.input.text(e);
				return this;
			}
		},
		getItem: function(e) {
			return this.attributes[e];
		},
		setItem: function(e, v) {
			this.attributes[e] = v;
			return this;
		}
	};
	/*
	 * 动态页面组件：LOL
	 */
	var cLol = function(container, profile, runtime) {
		return new ctlLol(container, profile, runtime);
	},

	ctlLol = function(container, profile, runtime) {
		var a = this;
		a.id = profile.cId;
		a.type = "LOL";
		a.disabled = false;
		a.instance = runtime.instance;
		a.container = container;
		a.runtime = runtime;
		a.path = (runtime.namespace ? (runtime.namespace + '.' + a.id) : a.id);
		a.profile = profile;
		a.objProp = profile.ot || {};
		a.custProp = profile.o2 || {};
		a.parentDisabled = a.disabled = false;
		a.attributes = {};
		//console.log(a);

		var q = ctlStyle(a), style = q.style, outerStyle = q.outerStyle, innerStyle = q.innerStyle, clazz = q.clazz;
		clazz.push('dyn_lol');
		style['position'] = 'fixed';
		style['top'] = 0;
		style['right'] = 0;
		style['bottom'] = 0;
		style['z-index'] = 1;
		style['overflow'] = 'auto';
		style['margin-top'] = '1em';
		delete style['left'];
		delete style['width'];
		delete style['height'];

		a.ul = $('<ul data-type="' + a.type + '" data-path="' + a.path + '" class="' + clazz.join(' ') + '" style="' + getStyles(style) + '" href="javascript:;">' + (profile.lD || '') + '</a>').appendTo(container);
		var letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', cmd = a.custProp.lol;
		for(var i=0; i<letters.length; i++) {
			$('<a href="javascript:;">' + letters[i] + '</a>').appendTo($('<li></li>').appendTo(a.ul)).on('click', function(e) {
				e.preventDefault();
				e.stopPropagation();
				a.instance.doCmd('P' + cmd, {CTRL: a, EVENT: e.target.innerText}, runtime, a.id);
			})
		}

		a.instance.registerEvent('_internal_stack_resize', function(size) {
			a.ul.css({
				top: size.top + 'px',
				bottom: size.bottom + 'px'
			})
		}, runtime)

		if (a.custProp.s_state)
			a.state(a.custProp.s_state);
		makeValueAndState(a);

		return a;
	};

	ctlLol.prototype = {
		state : function(e) {
			if (e == undefined)
				return this._state;
			else {
				this._state = e;
				if (e == 1)
					this.ul.hide();
				else {
					this.ul.show();
					this.disable(e == 2);
				}
			}
		},
		disable : function(e, byParent) {
			if (byParent) {
				this.ul.toggleClass('disabled', e || this.disabled);
				this.parentDisabled = e;
			} else {
				this.ul.toggleClass('disabled', e || this.parentDisabled);
				this.disabled = e;
			}
		},

		val : function(t) {
		},
		evt : function(e) {
		},
		bind : function(e, callback) {
			this.ul.bind(e, callback);
		},
		getItem: function(e) {
			return this.attributes[e];
		},
		setItem: function(e, v) {
			this.attributes[e] = v;
			return this;
		}
	};

	/*
	 * 动态页面组件：Button
	 */
	var cButton = function(container, profile, runtime, data, rowNum) {
		return new ctlButton(container, profile, runtime, data, rowNum);
	},

	ctlButton = function(container, profile, runtime, data, rowNum) {
		var a = this;
		a.id = profile.cId + (rowNum == undefined? '' : ('-' + rowNum));
		a.type = "BUTTON";
		a.disabled = false;
		a.instance = runtime.instance;
		a.container = container;
		a.runtime = runtime;
		a.path = runtime.namespace + '.' + a.id;
		a.profile = profile;
		a.objProp = profile.ot || {};
		a.custProp = profile.o2 || {};
		a.xitemRow = rowNum;
		a.xitemData = data;
		a.parentDisabled = a.disabled = false;
		a.attributes = {};
		//console.log(a);

		var q = ctlStyle(a), style = q.style, outerStyle = q.outerStyle, innerStyle = q.innerStyle, clazz = q.clazz;
		if (! style['display'])
			style['display'] = 'inline-block'

		if (profile.sty == 'ngs_goback' || profile.sty == 'ngs_forward') {
			// 方向特殊按钮
			style['width'] = style['height'] = '26px';
			a.input = $('<button type="button" data-type="' + a.type + '" data-path="' + a.path + '" class="' + clazz.join(' ') + '" style="' + getStyles(style, outerStyle, innerStyle) + '" />').appendTo(container);
		} else {
			if (a.objProp.c == '1') {
				// 下拉风格按钮
				clazz.push('dyn_dropdown');
				a.dom = $('<div data-type="' + a.type + '" data-path="' + a.path + '" class="' + clazz.join(' ') + '" style="' + getStyles(style, outerStyle, innerStyle) + '" />').appendTo(container);
				var icon = '', label = '', menu = [];
				if (a.objProp.i)
					icon = $F.parseIcon(a.objProp.i);
				if (profile.lD !== undefined)
					label = profile.lD;
				var cachekey = 'dyn_dropdown_' + runtime.struct.id + '.' + profile.cId,
					options = {
						icon: icon,
						label: label,
						menu: menu,
						defAct: a.custProp.defact || 0,
						hoverable: a.custProp.hover,
						fixLayerWidth: (a.custProp.fixlw?false:true),
						selected: function(menuIndex) {
							console.info('save dropdown menu item: ' + menuIndex);
							CmdUtils.setLocalValue(runtime, cachekey, menuIndex);
						}
					}

				var defAct = parseInt(CmdUtils.getValue(cachekey, 0, runtime));
				if (! isNaN(defAct)) {
					options.defAct = defAct;
					//console.log('发现dropdown按钮默认选项: ' + defAct);
				}

				// 收集菜单项
				$.each(a.objProp.list, function(i, v){
					var icon, k;
					if (v[0]) {
						k = v[0].indexOf('#');
						if (k !== -1)
							icon = '<i class="' + $F.fas(v[0].substring(0, k)) + ' fa-fw" style="color:' + v[0].substring(k) + '"></i>';
						else
							icon = '<i class="' + $F.fas(v[0]) + ' fa-fw"></i>';
					} else
						icon = '';
					var label = (v.length > 1)? v[1] : 'sep';
					var cmd = (v.length > 2)? v[2] : '';
					var state, stateVar = (v.length > 3)? v[3] : '';
					if (stateVar)
						state = a.instance.getValue(stateVar, runtime);
					else
						state = 0;

					var item = {
						id: Guid.raw(),
						icon: icon,
						label: label,
						state: state,
						callback: (cmd ? function(){
							a.instance.doCmd('P' + cmd, {CTRL: a}, runtime, a.id);
						} : false)
					};
					menu.push(item);
					if (stateVar) {
						a.instance.bindValue(stateVar, a, function(e) {
							item.state = e.data;
							a.input.state(item);
						})
					}
					if (state > 0){
						if (options.defAct == i)
							delete options.defAct;
					}
				});

				if (a.objProp.j !== '')
					options.radius = a.objProp.j + 'px';
				a.input = a.dom.wisDropdown(options);
			} else {
				// 普通按钮
				a.dom = a.input = $('<button type="button" data-type="' + a.type + '" data-path="' + a.path + '" class="' + clazz.join(' ') + '" style="' + getStyles(style, outerStyle, innerStyle) + '"></button>').appendTo(container);
				var label = $('<span class="js_label">' + (profile.lD || '') + '</span>');
				if (!! a.objProp.i) {
					// 包含图标
					var icon = $F.parseIcon(a.objProp.i);
					if (icon.hasClass('pull-right')) {
						a.input.append(label);
						a.input.append(icon)
					} else {
						if (profile.lD && !icon.hasClass('vertical'))
							icon.addClass('pull-left')
						a.input.append(icon);
						a.input.append(label);
					}
					a.dom.addClass('dyn_valign')
				} else {
					a.input.append(label);
				}
				if (a.objProp.j !== '')
					a.input.css({
						'border-radius': a.objProp.j + 'px'
					})
			}
		}
		if (a.custProp.tooltip)
			a.input.attr('title', a.custProp.tooltip);

		if (a.custProp.s_state)
			a.state(a.custProp.s_state);
		makeValueAndState(a, data, rowNum);
		return a;
	};

	ctlButton.prototype = {
		state : function(e) {
			if (e == undefined)
				return this._state;
			else {
				this._state = e;
				if (e == 1)
					this.dom.hide();
				else {
					this.dom.show();
					this.disable(e == 2);
				}
			}
		},
		disable: function(e, byParent) {
			if (byParent) {
				if (this.objProp.c == '1')
					this.input.disable(e || this.disabled);
				else
					this.input.prop('disabled', e || this.disabled);
				this.parentDisabled = e;
			} else {
				if (this.objProp.c == '1')
					this.input.disable(e || this.parentDisabled);
				else
					this.input.prop('disabled', e || this.parentDisabled);
				this.disabled = e;
			}
		},

		val : function(t) {
			if (t == undefined)
				return this.value;
			else
				this.value = t;
			return this;
		},
		evt : function(e) {
			if (e == undefined)
				return {
					type: 0,
					data: this.val()
				}
			else
				this.val(e.data);
		},

		bind : function(e, callback) {
			this.input.bind(e, callback);
		},

		trigger : function(e) {
			this.input.trigger(e);
		},

		triggerChange : function(e) {
			this.input.trigger('click');
		},

		focus : function() {
			this.input.focus();
		},

		driftLayer : function(layer) {
			var owner = this.dom;
			layer.drift(owner.offset().top, owner.offset().left, owner.offset().top + owner.outerHeight(), owner.offset().left + owner.outerWidth());
		},

		toggle : function(e) {
			var a = this;
			a.toggleClass(a.profile.ot.ss, a.profile.ot.sv == e);
		},
		toggleClass : function(className, expression) {
			this.input.toggleClass(className, expression);
		},

		errMask : function() {
			this.input.css({
				color: 'red',
				'font-weight': 'bolder',
				'border': '1px solid #FF0000'
			})
		},

		fullscreenTriger : function() {
			var a = this;
			a.input.on('click', function(e) {
				H5Utils.fullscreen(a.container);
			})
		},

		setStyle : function(cssStyle) {
			this.input.css(cssStyle);
		},

		html : function(t) {
			if (t == undefined)
				return this.input.html();
			else {
				this.input.html(t);
				return this;
			}
		},

		text : function(e) {
			if (e == undefined)
				return this.profile.lD || this.input.text();
			else {
				this.input.text(e);
				return this;
			}
		},

		tooltip: function(e, direct) {
			if (e == undefined)
				return this.input.attr('title');

			this.input.attr('title', e);
			if (direct)
				Tipped.create(this.input, { position: direct });
			else
				Tipped.create(this.input)
			return this;
		},
		getItem: function(e) {
			return this.attributes[e];
		},
		setItem: function(e, v) {
			this.attributes[e] = v;
			return this;
		}
	};

	/*
	 * 动态页面组件：Checkbox
	 */
	var cCheckbox = function(container, profile, runtime, data, rowNum) {
		return new ctlCheckbox(container, profile, runtime, data, rowNum);
	},

	ctlCheckbox = function(container, profile, runtime, data, rowNum) {
		var a = this;
		a.id = profile.cId + (rowNum == undefined? '' : ('-' + rowNum));
		a.type = "CHECKBOX";
		a.disabled = false;
		a.instance = runtime.instance;
		a.container = container;
		a.runtime = runtime;
		a.path = runtime.namespace + '.' + a.id;
		a.profile = profile;
		a.objProp = profile.ot || {};
		a.custProp = profile.o2 || {};
		a.xitemRow = rowNum;
		a.value = a.objProp.v; //Verify.isDigit(a.objProp.v) ? parseFloat(a.objProp.v) : a.objProp.v;
		a.inputName = a.instance.id + '_' + a.runtime.namespace.replaceAll('\\.', '_') + '_ckb_' + (profile.vV ? profile.vV.replaceAll('\\.', '_') : 'NA');
		a.parentDisabled = a.disabled = false;
		a.attributes = {};
		//console.log(a);

		var q = ctlStyle(a), style = q.style, outerStyle = q.outerStyle, innerStyle = q.innerStyle, clazz = q.clazz;
		style['line-height'] = (profile.height-2) + 'px';
		innerStyle['font-size'] = 'inherit';
		a.dom = $('<div data-type="' + a.type + '" data-path="' + a.path + '" class="' + clazz.join(' ') + ' dyn_ckb" style="' + getStyles(style, outerStyle) + '" />').appendTo(container);
		var fakeBox = (a.dom.css('display') == 'flex') ? a.dom : ($('<div class="wl" />').appendTo(a.dom));
		a.input = $('<input type="checkbox" name="' + a.inputName + '" data-path="' + a.path + '" value="' + a.value  + '" />');
		a.lb = $('<label class="unselectable /">').appendTo(fakeBox);
		a.lb.append(a.input);
		if (profile.lD)
			a.lb.append($('<span />').text(profile.lD));

		if (profile.sty)
			a.input.addClass(profile.sty);

		a.input.on('click', function(e){
			if (a.input.prop('checked')) {
				// 处理互斥
				$('input[type=checkbox][name="' + a.inputName + '"]:checked', container).each(function(){
					var ckb = $(this);
					if (ckb.attr('data-path') !== a.path)
						ckb[0].checked = false;
				})
			}
			// console.log(a.evt());
			if (profile.vV)
				a.instance.fireValue(profile.vV, runtime, a.evt(), a);

			if (H5Utils.isFirefox)
				a.input.trigger('change')
		});

		if (a.custProp.s_state)
			a.state(a.custProp.s_state);
		makeValueAndState(a, data, rowNum);
		return a;
	};

	ctlCheckbox.prototype = {
		state : function(e) {
			if (e == undefined)
				return this._state;
			else {
				this._state = e;
				if (e == 1)
					this.dom.hide();
				else {
					this.dom.show();
					this.disable(e == 2);
					this.input.prop('readonly', (e == 3));
				}
			}
		},
		disable: function(e, byParent) {
			if (byParent) {
				this.input.prop('disabled', e || this.disabled);
				this.parentDisabled = e;
			} else {
				this.input.prop('disabled', e || this.parentDisabled);
				this.disabled = e;
			}
		},

		val : function(t) {
			var a = this;
			if (! arguments.length) {
				if (a.input.prop('checked'))
					return a.value;
				else
					return a.profile.vV ? a.instance.getValueByPropertyName(a.runtime, a.profile.vV, '') : '';
			} else {
				// console.log('Checkbox[' + this.value + '] update:' + t);
				a.input.prop('checked', (t == a.value));
				return this;
			}
		},

		evt : function(e) {
			if (e == undefined)
				return {
					type: 0,
					data: this.val()
				}
			else
				this.val(e.data);
		},

		bind : function(e, callback) {
			this.input.on(e, callback);
		},

		triggerChange : function(e) {
			this.input.trigger('click');
		},

		focus : function() {
			this.input.focus();
		},

		driftLayer : function(layer) {
			var owner = this.dom;
			layer.drift(owner.offset().top, owner.offset().left, owner.offset().top + owner.outerHeight(), owner.offset().left + owner.outerWidth());
		},

		setStyle : function(cssStyle) {
			this.dom.css(cssStyle);
		},

		label : function(e) {
			if (e == undefined)
				return this.lb ? this.lb.text() : '';
			else {
				this.lb && this.lb.html(e);
				return this;
			}
		},
		getItem: function(e) {
			return this.attributes[e];
		},
		setItem: function(e, v) {
			this.attributes[e] = v;
			return this;
		}
	};

	/*
	 * 动态页面组件：Radio
	 */
	var cRadio = function(container, profile, runtime, data, rowNum) {
		return new ctlRadio(container, profile, runtime, data, rowNum);
	},

	ctlRadio = function(container, profile, runtime, data, rowNum) {
		var a = this;
		a.id = profile.cId + (rowNum == undefined? '' : ('-' + rowNum));
		a.type = "RADIO";
		a.disabled = false;
		a.instance = runtime.instance;
		a.container = container;
		a.runtime = runtime;
		a.path = runtime.namespace + '.' + a.id;
		a.profile = profile;
		a.objProp = profile.ot || {};
		a.custProp = profile.o2 || {};
		a.xitemRow = rowNum;
		a.value = a.objProp.v;
		a.inputName = a.instance.id + '_' + a.runtime.namespace.replaceAll('\\.', '_') + '_ckb_' + (profile.vV ? profile.vV.replaceAll('\\.', '_') : 'NA');
		a.parentDisabled = a.disabled = false;
		a.attributes = {};
		//console.log(a);

		var q = ctlStyle(a), style = q.style, outerStyle = q.outerStyle, innerStyle = q.innerStyle, clazz = q.clazz;
		style['line-height'] = (profile.height-2) + 'px';
		innerStyle['font-size'] = 'inherit';
		a.dom = $('<div data-type="' + a.type + '" data-path="' + a.path + '" class="' + clazz.join(' ') + '" style="' + getStyles(style, outerStyle) + '" />').appendTo(container);
		a.input = $('<input type="radio" name="' + a.inputName + '" id="' + a.path + '_ctl_rd" value="' + ((rowNum !== undefined) ? rowNum : a.objProp.v)  + '" />').appendTo(a.dom);
		a.lb = $('<label for="' + a.path + '_ctl_rd"></label>').appendTo(a.dom);
		if (a.objProp.i) {
			var icon = $F.parseIcon(a.objProp.i);
			if (a.profile.lD)
				icon.addClass('pull-left');
			a.lb.append(icon);
		}
		if (a.profile.lD)
			a.lb.append(profile.lD);

		a.input.on('click', function(e){
			if (profile.vV)
				a.instance.fireValue(profile.vV, runtime, a.evt(), a);
		});

		if (a.custProp.s_state)
			a.state(a.custProp.s_state);
		makeValueAndState(a, data, rowNum);
		return a;
	};

	ctlRadio.prototype = {
		state : function(e) {
			if (e == undefined)
				return this._state;
			else {
				this._state = e;
				if (e == 1)
					this.dom.hide();
				else {
					this.dom.show();
					this.disable(e == 2);
					this.input.prop('readonly', (e == 3));
				}
			}
		},
		disable: function(e, byParent) {
			if (byParent) {
				this.input.prop('disabled', e || this.disabled);
				this.parentDisabled = e;
			} else {
				this.input.prop('disabled', e || this.parentDisabled);
				this.disabled = e;
			}
		},

		val : function(t) {
			if (t == undefined)
				return $('input[name=' + $F.escapeSpecialCharForSelector(this.inputName) + ']:checked').val();
			else {
				$('input[name=' + $F.escapeSpecialCharForSelector(this.inputName) + '][value=\'' + t + '\']').prop('checked', true);
				return this;
			}
		},

		evt : function(e) {
			if (e == undefined)
				return {
					type: 0,
					data: this.val()
				}
			else
				this.val(e.data);
		},

		bind : function(e, callback) {
			this.input.bind(e, callback);
		},

		triggerChange : function(e) {
			this.input.trigger('click');
		},

		focus : function() {
			this.input.focus();
		},

		driftLayer : function(layer) {
			var owner = this.dom;
			layer.drift(owner.offset().top, owner.offset().left, owner.offset().top + owner.outerHeight(), owner.offset().left + owner.outerWidth());
		},

		setStyle : function(cssStyle) {
			this.dom.css(cssStyle);
		},

		label : function(e) {
			if (e == undefined)
				return this.lb ? this.lb.text() : '';
			else {
				this.lb && this.lb.html(e);
				return this;
			}
		},
		getItem: function(e) {
			return this.attributes[e];
		},
		setItem: function(e, v) {
			this.attributes[e] = v;
			return this;
		}
	};

	/*
	 * 动态页面组件：List
	 */
	var cList = function(container, profile, runtime, data, rowNum) {
		return new ctlList(container, profile, runtime, data, rowNum);
	},

	ctlList = function(container, profile, runtime, data, rowNum) {
		var a = this;
		a.id = profile.cId;
		a.type = "LIST";
		a.disabled = false;
		a.instance = runtime.instance;
		a.container = container;
		a.runtime = runtime;
		a.path = runtime.namespace + '.' + a.id;
		a.profile = profile;
		a.objProp = profile.ot || {};
		a.custProp = profile.o2 || {};
		a.xitemRow = rowNum;
		a.xitemData = data;
		// 选值是否需要包装成SQL格式, 1=需要在每个选值上加上单引号
		a.valueStyle = 0;
		a.changeCalls = [];
		a.parentDisabled = a.disabled = false;
		a.attributes = {};
		// console.log(a);

		var q = ctlStyle(a), style = q.style, outerStyle = q.outerStyle, innerStyle = q.innerStyle, clazz = q.clazz;
		a.dom = $('<div data-type="' + a.type + '" data-path="' + a.path + '" class="' + clazz.join(' ') + '" style="' + getStyles(style, outerStyle, innerStyle) + '" />').appendTo(container);
		if (a.profile.vV)
			a.dom.attr('data-ref', a.profile.vV);

		a.wisList = a.dom.wisList({
			lang: $E.lang,
			multiSelect: a.objProp.count || 0,
			checkable: a.objProp.chkFlag,
			actionBar : a.custProp.actbar,
			tabIndex : 0,
			onChange : function(data) {
				var str = "";
				$.each(data, function(i, v){
					if (a.valueStyle)
						str += ",'" + v.value.toString().replace2("'", "''") + "'";
					else
						str += "," + v.value.toString();
				})

				if (str.length > 0)
					a.value = str.substring(1);
				else
					a.value = str;
				if (profile.vV)
					a.instance.fireValue(profile.vV, runtime, a.evt(), a);
				a.triggerChange();
			}
		});
		a.value = '';

		a.setOptions = function(keyField, valueField, data, value) {
			makeOptions(keyField, valueField, sqldata(data, [keyField, valueField]), value);
		};

		var makeOptions = function(keyField, valueField, data, value) {
			var cs = [];
			$.each(data, function(i, v) {
				cs.push({
					label: Helper.filter(v[keyField]),
					value: v[valueField]
				})
			})
			a.wisList.clear().setData(cs);
			if (value) {
				// console.info('初始化列表选项值：' + value);
				a.val(value);
			}
		};
		// 从实例获得默认值
		if (a.objProp.flag !== undefined) {
			if (a.objProp.flag == 0) {
				// 处理预加载数据选项
				if (a.objProp.data) {
					var rs = [];
					for(var key in a.objProp.data) {
						rs.push({
							label: Helper.filter(key),
							value: a.objProp.data[key]
						})
					}
					a.wisList.setData(rs);
					if (profile.vV)
						a.val(a.instance.getValue(profile.vV, runtime));
				}
			} else if (a.objProp.flag == 1){
				// 处理动态加载数据选项
				if (a.objProp.data && a.objProp.data.sql) {
					var cacheKey = a.objProp.data.c ? (runtime.struct.id + '.' + a.objProp.data.c) : '';
					if (cacheKey && runtime.project.cache[cacheKey]) {
						// 已经有缓存
						a.setOptions(a.objProp.data.s,
								a.objProp.data.v,
								runtime.project.cache[cacheKey],
								(profile.vV ? a.instance.getValue(profile.vV, runtime) : a.val()));
					} else {
						var valueField = a.objProp.data.v;
						if (valueField && valueField.startWith('@')) {
							a.valueStyle = 1;
							valueField = valueField.substring(1);
						}

						// 变量传参遍历
						var params = {};
						if (profile.relvars) {
							$.each(profile.relvars, function(i, v) {
								if (v.pro.startWith('@')) {
									var x = parseInt(v.pro.substring(1));
									params[v.Rel] = a.xitemData[x-1];
									a.xitemListener = a.xitemListener || {};
									a.xitemListener[x] = function(e) {
										params[v.Rel] = e;
										kvCtl_getOptions(a, cacheKey, a.objProp.data.sql, params, a.objProp.data.s, valueField, a.val());
									}
								} else {
									params[v.Rel] = a.instance.getValue(v.pro, runtime);
									a.instance.bindValue(v.pro, a, function(e) {
										params[v.Rel] = e.data;
										kvCtl_getOptions(a, cacheKey, a.objProp.data.sql, params, a.objProp.data.s, valueField, a.val());
									});
								}
							});
						}
						kvCtl_getOptions(a, cacheKey, a.objProp.data.sql, params, a.objProp.data.s, valueField, (profile.vV ? a.instance.getValue(profile.vV, runtime) : a.val()));
					}
				}
			} else if (a.objProp.flag == 2) {
				// 处理全局SQL数据项
				//console.info(a.objProp);
				if (a.objProp.data && a.objProp.data.pubKey && a.objProp.data.s && a.objProp.data.v) {
					var params = [];
					$F.ognl(a.objProp.data.f, function(propertyName) {
						params.push(propertyName);
					})
					//console.log('JSONSQL bind: ', params);
					var ognlOptions = function(value) {
						var jsonSql = $F.ognl(a.objProp.data.f, function(propertyName) {
							return getValue(a.instance, propertyName, a.runtime);
						})
						var data = a.instance.project.queryCodetable(a.objProp.data.pubKey, jsonSql);
						if ($E.debug)
							console.log('JSONSQL[' + a.objProp.data.pubKey + ']: ' + jsonSql, data)
						var valueField = (a.objProp.data.v || '').trim().toUpperCase();
						if (valueField && valueField.startWith('@')) {
							a.valueStyle = 1;
							valueField = valueField.substring(1);
						}
						makeOptions(a.objProp.data.s.toUpperCase(), valueField, data, value)
					}
					if (params.length > 0) {
						// 使用变量入参
						$.each(params, function(i, v) {
							a.instance.bindValue(v, a, function(e) {
								ognlOptions(profile.vV ? a.instance.getValue(profile.vV, runtime) : a.val())
							})
						})
					}
					ognlOptions(profile.vV ? a.instance.getValue(profile.vV, runtime) : a.val());
				}
			} else {
				// 处理绑定变量的数据源
				if (a.objProp.data['var']) {
					a.instance.bindValue(a.objProp.data['var'], a, function(e) {
						if (e.type == 0)
							a.setData(e.data, (profile.vV ? a.instance.getValue(profile.vV, runtime) : a.val()));
					})
					a.setData(a.instance.getValue(a.objProp.data['var'], runtime),
							(profile.vV ? a.instance.getValue(profile.vV, runtime) : a.val()));
				}
			}
		}

		if (a.custProp.s_state)
			a.state(a.custProp.s_state);
		makeValueAndState(a, data, rowNum, true);
		return a;
	};

	ctlList.prototype = {
		state : function(e) {
			if (e == undefined)
				return this._state;
			else {
				this._state = e;
				if (e == 1)
					this.dom.hide();
				else {
					this.dom.show();
					this.disable(e == 2);
				}
			}
		},
		disable: function(e, byParent) {
			if (byParent) {
				this.wisList.disable(e || this.disabled);
				this.parentDisabled = e;
			} else {
				this.wisList.disable(e || this.parentDisabled);
				this.disabled = e;
			}
		},

		setData : function(data, value) {
			var a = this, cs = [];
			$.each(data, function(i, v) {
				cs.push({
					label: Helper.filter(v[a.objProp.data.s]),
					value: v[a.objProp.data.v]
				})
			})
			a.wisList.clear().setData(cs);
			if (value) {
				// console.info('初始化列表选项值：' + value);
				a.val(value);
			}
		},

		val : function(t) {
			var a = this;
			if (t == undefined) {
				return a.value;
			} else {
				// console.log('得到赋值：' + t);
				a.value = t;
				a.wisList.clear();
				if (t != null) {
					if ($.type(t) == 'string') {
						var s = t.split(',');
						if (a.valueStyle) {
							$.each(s, function(i, v){
								s[i] = rmMarks(v);
							})
						}
						a.wisList.select(s);
					} else
						a.wisList.select([t]);
				}
				return a;
			}
		},

		evt : function(e) {
			if (e == undefined)
				return {
					type: 0,
					data: this.val()
				}
			else
				this.val(e.data);
		},
		bind : function(e, callback) {
			if (e == 'change')
				this.changeCalls.push(callback)
		},

		triggerChange : function(e) {
			$.each(this.changeCalls, function(){
				this();
			})
		},

		setStyle : function(cssStyle) {
			this.dom.css(cssStyle);
		},
		getItem: function(e) {
			return this.attributes[e];
		},
		setItem: function(e, v) {
			this.attributes[e] = v;
			return this;
		}
	};

	/*
	 * 动态页面组件：ListCI
	 */
	var cListci = function(container, profile, runtime, data, rowNum) {
		return new ctlListci(container, profile, runtime, data, rowNum);
	},

	ctlListci = function(container, profile, runtime, data, rowNum) {
		var a = this;
		a.id = profile.cId;
		a.type = "LISTCI";
		a.disabled = false;
		a.instance = runtime.instance;
		a.container = container;
		a.runtime = runtime;
		a.path = runtime.namespace + '.' + a.id;
		a.profile = profile;
		a.objProp = profile.ot || {};
		a.custProp = profile.o2 || {};
		// 选值是否需要包装成SQL格式, 1=需要在每个选值上加上单引号
		a.valueStyle = 0;
		a.parentDisabled = a.disabled = false;
		a.attributes = {};
		//console.log(a);

		var q = ctlStyle(a), style = q.style, outerStyle = q.outerStyle, innerStyle = q.innerStyle, clazz = q.clazz;
		a.dom = $('<div data-type="' + a.type + '" data-path="' + a.path + '" class="' + clazz.join(' ') + '" style="' + getStyles(style, outerStyle, innerStyle) + '" />').appendTo(container);
		a.wisListCI = a.dom.wisListCI({
			multiSelect: profile.gridR || 0,
			onCheck : function(data, row, state) {
				data.state = state;
				if (data.ckbPid)
					a.instance.fireValue(data.ckbPid, runtime, {type:0, data: (state?data.ckbValue:'')}, a);
				if (! state) {
					data.value = '';
					a.wisListCI.refresh(row);
					if (data.inpVarId)
						a.instance.fireValue(data.inpVarId, runtime, {type:0, data:data.value}, a)
				}
			},
			onChange : function(data, row, value) {
				data.value = value;
				if (data.inpVarId)
					a.instance.fireValue(data.inpVarId, runtime, {type:0, data:value}, a);
			}
		});

		var data = runtime.project.getCache(a.id);
		if (data == null) {
			data = [];
			$.each(profile.cells, function(i, cell){
				var item = {
					label: cell.other,
					state: cell.varId?(a.instance.getValue(cell.varId, runtime) == cell.value):false,
					value: cell.inpVarId?a.instance.getValue(cell.inpVarId, runtime):'',
					// customer fields
					ckbPid: cell.varId,
					ckbValue: cell.value,
					inpVarId: cell.inpVarId,
					editable: cell.inpVarId?true:false
				};
				data.push(item);
				if (cell.varId){
					a.instance.bindValue(cell.varId, a, function(e) {
						item.state = (e.data == cell.value);
						a.wisListCI.refresh(i);
					})
				}
				if (cell.inpVarId) {
					a.instance.bindValue(cell.inpVarId, a, function(e) {
						item.value = e.data;
						a.wisListCI.refresh(i);
					})
				}
			})
			runtime.project.putCache(a.id, data);
		}
		a.wisListCI.setData(data);

		if (a.custProp.s_state)
			a.state(a.custProp.s_state);
		makeValueAndState(a, data, rowNum);
		return a;
	};

	ctlListci.prototype = {
		state : function(e) {
			if (e == undefined)
				return this._state;
			else {
				this._state = e;
				if (e == 1)
					this.dom.hide();
				else {
					this.dom.show();
					this.disable(e == 2);
				}
			}
		},
		disable: function(e, byParent) {
			if (byParent) {
				this.dom.toggleClass('disabled', e || this.disabled);
				this.parentDisabled = e;
			} else {
				this.dom.toggleClass('disabled', e || this.parentDisabled);
				this.disabled = e;
			}
		},

		val : function(t) {
		},
		evt : function(e) {
		},
		bind : function(e, callback) {
		},

		setStyle : function(cssStyle) {
			this.dom.css(cssStyle);
		},
		getItem: function(e) {
			return this.attributes[e];
		},
		setItem: function(e, v) {
			this.attributes[e] = v;
			return this;
		}
	};

	/*
	 * 动态页面组件：Combo
	 */
	var cCombox = function(container, profile, runtime, data, rowNum) {
		return new ctlCombox(container, profile, runtime, data, rowNum);
	},

	ctlCombox = function(container, profile, runtime, data, rowNum) {
		var a = this;
		a.id = profile.cId + (rowNum == undefined? '' : ('-' + rowNum));
		a.type = "COMBOX";
		a.disabled = false;
		a.instance = runtime.instance;
		a.container = container;
		a.runtime = runtime;
		a.path = runtime.namespace + '.' + a.id;
		a.profile = profile;
		a.objProp = profile.ot || {};
		a.custProp = profile.o2 || {};
		a.xitemRow = rowNum;
		a.xitemData = data;
		a.valueStyle = 0;
		a.changeCalls = [];
		a.parentDisabled = a.disabled = false;
		a.attributes = {};
		// console.info(a);

		var q = ctlStyle(a), style = q.style, outerStyle = q.outerStyle, innerStyle = q.innerStyle, clazz = q.clazz, attrs = '';
		innerStyle['font-size'] = 'inherit';
		if (a.objProp.h)
			attrs += ' placeholder="' + (a.objProp.h || '') + '"';
		if (a.custProp.required)
			attrs += ' required="required"'


		if (profile.lWidth > 0) {
			// 带标签控件
			clazz.push('wl');
			a.dom = $('<div data-type="' + a.type + '" data-path="' + a.path + '" class="' + clazz.join(' ') + '" style="' + getStyles(style, outerStyle) + '" />').appendTo(container);
			var fakeBox = (a.dom.css('display') === 'flex') ? a.dom : ($('<div class="wl" />').appendTo(a.dom));
			a.lb = $('<span class="dyn_as dyn_label" style="width:' + profile.lWidth + 'px; line-height:' + style['height'] + '"/>').text(profile.lD).appendTo(fakeBox);
			innerStyle['width'] = 'auto';
			if (a.custProp.multi || a.custProp.filterable) {
				a.input = $('<div class="wlc" style="' + getStyles(innerStyle) + '" />').appendTo(fakeBox);
				a.input = $('<div style="position:absolute;top:0;left:0;right:0;width:100%" />').appendTo(a.input);
			} else
				a.input = $('<select class="wlc" style="' + getStyles(innerStyle) + '" ' + attrs + '/>').appendTo(fakeBox);
		} else {
			if (style['width'] === 'auto' || style['height'] === 'auto') {
				a.dom = $('<div data-type="' + a.type + '" data-path="' + a.path + '" class="' + clazz.join(' ') + '" style="' + getStyles(style, outerStyle) + '" />').appendTo(container);
				if (a.custProp.multi || a.custProp.filterable)
					a.input = $('<div style="' + getStyles(innerStyle) + ';width:100%;height:100%" />').appendTo(a.dom);
				else
					a.input = $('<select style="' + getStyles(innerStyle) + ';width:100%;height:100%"' + attrs + '/>').appendTo(a.dom);
			} else {
				if (a.custProp.multi || a.custProp.filterable)
					a.dom = a.input = $('<div data-type="' + a.type + '" data-path="' + a.path + '" class="' + clazz.join(' ') + '" style="' + getStyles(style, outerStyle, innerStyle) + '" />').appendTo(container);
				else
					a.dom = a.input = $('<select data-type="' + a.type + '" data-path="' + a.path + '" class="' + clazz.join(' ') + '" style="' + getStyles(style, outerStyle, innerStyle) + '"' + attrs + '/>').appendTo(container);
			}
		}
		if (a.profile.vV)
			a.input.attr('data-ref', a.profile.vV);
		if (a.custProp.required)
			a.input.prop('required', true);

		if (a.custProp.multi || a.custProp.filterable) {
			a.input = a.input.wisCombox({
				tabIndex : 0,
				tip : a.objProp.tip,
				multi : a.custProp.multi,
				inputable : a.custProp.filterable,
				fixedWidth: false,
				onSelected : function(data) {
					// console.log(data)
					if (a.changeCalls)
						$.each(a.changeCalls, function(){
							this(null, data)
						})
				}
			})
		} else {
			a.input.on('keydown', function(e) {
				if (e.keyCode == 46) {
					a.input.val('').trigger('change');
				}
			}).data('ctrl', a);
			a.input.on('change', function(){
				var v = a.input.val()
				a.input.toggleClass('invalid', v == '' || v == null || v == undefined )
			})
		}

		if (a.custProp.defopt) {
			var cs = a.custProp.defopt.split('||');
			a.defaultOption = {
				label: cs[0] == '!' ? (a.custProp.multi ? $F.lang('ctls.comboxEmpty') : '') : cs[0],
				value: cs.length > 1 ? cs[1] : ''
			}
		}

		a.defaultValue = '';
		a.setOptions = function(keyField, valueField, data, value) {
			makeOptions(keyField, valueField, sqldata(data, [keyField, valueField]), value);
		};

		var makeOptions = function(keyField, valueField, data, value) {
			a.waitForOptions = false;
			if (a.custProp.multi || a.custProp.filterable) {
				var cs = [];
				if (a.defaultOption)
					cs.push(a.defaultOption)
				$.each(data, function(i, v) {
					cs.push({
						label: Helper.filter(v[keyField]),
						value: v[valueField]
					})
				})
				a.input.setData(cs);
			} else {
				a.input.empty();
				if (a.objProp.tip)
					a.input.append('<option value="" disabled>' + a.objProp.tip + '</option>');
				if (a.defaultOption)
					a.input.append('<option value="' + a.defaultOption.value + '">' + a.defaultOption.label + '</option>')
				$.each(data, function(i, v) {
					// 去除下拉框的value值trim，由于该值可能是各种数据类型，并非字符串独一
					// console.log(valueField + ' = ' + v[valueField], v)
					a.input.append('<option value="' + Helper.filterXSS(v[valueField] + '').trim() + '">' + Helper.filterXSS(v[keyField]) + '</option>');
				})
			}

			var newValue = (value == undefined)? a.defaultValue:value;
			// console.log('Set previous value:' + newValue);
			a.val(newValue);
			if (value == undefined && a.defaultValue != '') {
				// 必须是脚本刷新选项情况下
				//console.log('[COMBOX][' + a.id + '] - defaultValue:' + a.defaultValue)
				a.input.trigger('change');
			}
		}

		a.input.empty();
		if (a.objProp.flag == 0) {
			// 处理预加载数据选项
			// console.info(a.objProp)
			if (a.objProp.data) {
				var v;
				if (a.custProp.multi || a.custProp.filterable) {
					var cs = [];
					if (a.defaultOption)
						cs.push(a.defaultOption)
					for(var key in a.objProp.data) {
						v = a.objProp.data[key];
						$F.ognl(a.objProp.data[key], function(propertyName){
							v = a.instance.getValue(propertyName, a.runtime)
						})
						cs.push({
							label: Helper.filter(key),
							value: v
						})
					}
					a.input.setData(cs)
				} else {
					if (a.objProp.tip)
						a.input.append('<option value="" disabled>' + a.objProp.tip + '</option>');
					if (a.defaultOption)
						a.input.append('<option value="' + a.defaultOption.value + '">' + a.defaultOption.label + '</option>')
					for(var key in a.objProp.data) {
						v = a.objProp.data[key];
						$F.ognl(a.objProp.data[key], function(propertyName){
							v = a.instance.getValue(propertyName, a.runtime)
						})
						// 去除下拉框的value值trim，由于该值可能是各种数据类型，并非字符串独一
						a.input.append('<option value="' + Helper.filterXSS(v) + '">' + Helper.filterXSS(key) + '</option>');
					}
				}
			}
			if (profile.vV)
				a.val(a.instance.getValue(profile.vV, runtime));
			else
				a.val('');
		} else if (a.objProp.flag == 1) {
			// 处理动态加载数据选项
			if (a.objProp.data && a.objProp.data.sql) {
				var vf = a.objProp.data.v, lf = a.objProp.data.s, sql = a.objProp.data.sql;
				if (vf[0] == '@') {
					a.valueStyle = 1;
					vf = vf.substring(1);
				}
				var cacheKey = a.objProp.data.c ? (runtime.struct.id + '.' + a.objProp.data.c) : '';
				if (cacheKey && runtime.project.cache[cacheKey]) {
					// 已经有缓存
					a.setOptions(lf, vf, runtime.project.cache[cacheKey], undefined);
				} else {
					a.waitForOptions = true;
					// 变量传参遍历
					var params = {};
					if (profile.relvars) {
						// console.log(profile.relvars)
						$.each(profile.relvars, function(i, v){
							if (v.pro.startWith('@')) {
								var x = parseInt(v.pro.substring(1));
								params[v.Rel] = a.xitemData[x-1];
								a.xitemListener = a.xitemListener || {};
								a.xitemListener[x] = function(e) {
									params[v.Rel] = e;
									kvCtl_getOptions(a, cacheKey, sql, params, lf, vf, a.input.val());
								}
							} else {
								params[v.Rel] = a.instance.getValue(v.pro, runtime);
								a.instance.bindValue(v.pro, a, function(e){
									params[v.Rel] = e.data;
									// 创建回调选项方法
									var oldValue = profile.vV ? a.instance.getValue(profile.vV, runtime) : a.input.val();
									kvCtl_getOptions(a, cacheKey, sql, params, lf, vf, oldValue);
								});
							}
						});
					}
					kvCtl_getOptions(a, cacheKey, sql, params, lf, vf, (profile.vV ? a.instance.getValue(profile.vV, runtime) : undefined));
				}
			}
		} else if (a.objProp.flag == 2) {
			// 处理全局SQL数据项
			//console.info(a.objProp);
			if (a.objProp.data && a.objProp.data.pubKey && a.objProp.data.s && a.objProp.data.v) {
				var params = [];
				$F.ognl(a.objProp.data.f, function(propertyName) {
					params.push(propertyName);
				})
				//console.log('JSONSQL bind: ', params);
				var ognlOptions = function(value) {
					var jsonSql = $F.ognl(a.objProp.data.f, function(propertyName) {
						if (propertyName.startWith('@')) {
							var x = parseInt(propertyName.substring(1));
							return a.xitemData[x-1];
						} else {
							return getValue(a.instance, propertyName, a.runtime);
						}
					})
					var data = a.instance.project.queryCodetable(a.objProp.data.pubKey, jsonSql);
					if ($E.debug)
						console.log('JSONSQL[' + a.objProp.data.pubKey + ']: ' + jsonSql, data)

					var valueField = (a.objProp.data.v || '').trim().toUpperCase();
					if (valueField && valueField.startWith('@')) {
						a.valueStyle = 1;
						valueField = valueField.substring(1);
					}
					makeOptions(a.objProp.data.s.toUpperCase(), valueField, data, value)
				}
				if (params.length > 0) {
					// 使用变量入参
					$.each(params, function(i, v) {
						if (v.startWith('@')) {
							a.xitemListener = a.xitemListener || {};
							a.xitemListener[parseInt(v.substring(1))] = function(e) {
								ognlOptions(a.input.val())
							}
						} else {
							a.instance.bindValue(v, a, function(e) {
								ognlOptions(profile.vV ? a.instance.getValue(profile.vV, runtime) : a.input.val())
							})
						}
					})
				}
				ognlOptions(profile.vV ? a.instance.getValue(profile.vV, runtime) : undefined);
			}
		} else {
			// 处理绑定变量的数据源
			// console.error(a.objProp);
			if (a.objProp.data && a.objProp.data['var']) {
				a.instance.bindValue(a.objProp.data['var'], a, function(e) {
					if (e.type == 0)
						a.setData(e.data, (profile.vV ? a.instance.getValue(profile.vV, runtime) : a.input.val()));
				})
				a.setData(a.instance.getValue(a.objProp.data['var'], runtime),
						(profile.vV ? a.instance.getValue(profile.vV, runtime) : undefined));
			}
		}

		if (a.custProp.s_state)
			a.state(a.custProp.s_state);
		makeValueAndState(a, data, rowNum, true);
		return a;
	};

	ctlCombox.prototype = {
		state : function(e) {
			if (e == undefined)
				return this._state;
			else {
				this._state = e;
				if (e == 1)
					this.dom.hide();
				else {
					this.dom.show();
					this.input.removeClass('readonly')
					this.disable(e >= 2);
					if (e == 3)
						this.input.addClass('readonly');
				}
			}
		},
		disable: function(e, byParent) {
			var a = this;
			if (byParent) {
				if (a.custProp.multi || a.custProp.filterable)
					a.input.disable(e || a.disabled);
				else
					a.input.prop('disabled', e || a.disabled);
				a.parentDisabled = e;
			} else {
				if (a.custProp.multi || a.custProp.filterable)
					a.input.disable(e || a.parentDisabled);
				else
					a.input.prop('disabled', e || a.parentDisabled);
				a.disabled = e;
			}
		},

		setData : function(data, value) {
			var a = this;
			if (a.custProp.multi || a.custProp.filterable) {
				var cs = [];
				if (a.defaultOption)
					cs.push(a.defaultOption)
				$.each(data, function(i, v) {
					cs.push({
						label: Helper.filterXSS(v[a.objProp.data.s]),
						value: v[a.objProp.data.v]
					})
				})
				a.input.setData(cs);
			} else {
				a.input.empty();
				if (a.objProp.tip)
					a.input.append('<option value="" disabled>' + a.objProp.tip + '</option>');
				if (a.defaultOption)
					a.input.append('<option value="' + a.defaultOption.value + '">' + a.defaultOption.label + '</option>')
				$.each(data, function(i, v) {
					// 去除下拉框的value值trim，由于该值可能是各种数据类型，并非字符串独一
					a.input.append('<option value="' + Helper.filterXSS(v[a.objProp.data.v] + '').trim() + '">' + Helper.filterXSS(v[a.objProp.data.s]) + '</option>');
				})
			}

			var newValue = (value == undefined)? a.defaultValue:value;
			// console.log('Set previous value:' + newValue);
			a.val(newValue);
			if (value == undefined && a.defaultValue != '') {
				// 必须是脚本刷新选项情况下
				//console.log('[COMBOX][' + a.id + ' - defaultValue:' + a.defaultValue)
				a.input.trigger('change');
			}
		},

		val : function(t, unbind) {
			var a = this;
			if (t == undefined) {
				if (a.custProp.multi || a.custProp.filterable) {
					var l = [], v = [], b = a.input.val();
					if (a.custProp.multi) {
						$.each(b, function(){
							l.push(this.label);
							if (a.valueStyle)
								v.push('\'' + this.value + '\'');
							else
								v.push(this.value);
						})
						if (a.custProp.lbvar) {
							a.instance.fireValue(a.custProp.lbvar, a.runtime, {
								type: 0,
								data: l.join(',')
							})
						}
						return v.join(',');
					} else {
						if (a.custProp.lbvar) {
							a.instance.fireValue(a.custProp.lbvar, a.runtime, {
								type: 0,
								data: (b ? b.label : '')
							})
						}
						return b ? b.value : '';
					}
				} else {
					if (a.custProp.lbvar) {
						a.instance.fireValue(a.custProp.lbvar, a.runtime, {
							type: 0,
							data: a.input.find("option:selected").text()
						})
					}
					if (a.profile.vV)
						return a.instance.getValueByPropertyName(a.runtime, a.profile.vV, a.input.val());
					else
						return a.input.val();
				}
			} else {
				if (! a.waitForOptions) {
					if ($.type(t) == 'string')
						t = t.trim();

					//console.log('[COMBOX][' + a.id + ' - setValue:' + t)
					a.defaultValue = t;
					if (a.custProp.multi || a.custProp.filterable) {
						if (a.custProp.multi) {
							var s;
							if ($.type(t) == 'string') {
								s = t.split(',');
							} else {
								s = t;
							}
							if (a.valueStyle) {
								$.each(s, function(i, v){
									s[i] = rmMarks(v);
								})
							}
							a.input.val(s);
							if (a.custProp.lbvar) {
								var l = [];
								$.each(a.input.val(), function(){
									l.push(this.label);
								})
								a.instance.fireValue(a.custProp.lbvar, a.runtime, {
									type: 0,
									data: l.join(',')
								})
							}
						} else {
							a.input.val(t);
							var b = a.input.val();
							if (! unbind) {
								if (!b || !$F.equalValue(b.value,t)) {
									console.info('[' + a.path + ']当前选项中无匹配值：(' + t + ')');
									a.input.val('');
									if (a.profile.vV)
										a.instance.fireValue(a.profile.vV, a.runtime, {type: 0, data: ''}, a);
								}
							}
							if (a.custProp.lbvar) {
								a.instance.fireValue(a.custProp.lbvar, a.runtime, {
									type: 0,
									data: b ? b.label : ''
								})
							}
						}
					} else {
						a.input.val(t);
						if (! unbind) {
							if (t !== '' && a.input.val() == null) {
								// 赋值不成功，当前选项无匹配
								var cs = [];
								$('option', a.input).each(function(){
									cs.push(this.value)
								})
								console.info('[' + a.path + ']当前选项中无匹配值：(' + t + ')');
								a.input.val('');
								// console.log(t + '@' + (t + '').length);
								if (a.profile.vV)
									a.instance.fireValue(a.profile.vV, a.runtime, {type: 0, data: ''}, a);
							}
						}
						var v = a.input.val();
						a.input.toggleClass('invalid', v == '' || v == null || v == undefined )

						if (a.custProp.lbvar) {
							a.instance.fireValue(a.custProp.lbvar, a.runtime, {
								type: 0,
								data: a.input.find("option:selected").text()
							})
						}
					}
				} else
					a.defaultValue = t;
				return a;
			}
		},

		evt : function(e) {
			if (e == undefined)
				return {
					type: 0,
					data: this.val()
				}
			else
				this.val(e.data, e.unbind);
		},

		bind : function(e, callback) {
			var a = this;
			if (a.custProp.multi || a.custProp.filterable) {
				if (e == 'change')
					a.changeCalls.push(callback);
				else
					a.input.combox.bind(e, callback);
			} else
				a.input.bind(e, callback);
		},

		triggerChange : function(e) {
			this.input.trigger('change');
		},

		reset : function() {
			if (this.profile.vV) {
				var v = this.instance.getValue(this.profile.vV, this.runtime);
				this.val(v);//.triggerChange();
				//console.info('Combox reset to : ' + v);
			}
		},

		setStyle : function(cssStyle) {
			this.input.css(cssStyle);
		},

		focus : function() {
			this.input.focus();
		},

		label : function(e) {
			if (e == undefined)
				return (this.lb ? this.lb.text() : '');
			else {
				this.lb && this.lb.text(e);
				return this;
			}
		},

		checkAll : function() {
			if (this.custProp.multi)
				this.input.checkAll();
			else
				$F.err('Ctls - Combox', '非多选下拉控件，不可进行全选')
		},
		getItem: function(e) {
			return this.attributes[e];
		},
		setItem: function(e, v) {
			this.attributes[e] = v;
			return this;
		}
	};

	/*
	 * 动态页面组件：Table
	 */
	var cTable = function(container, profile, runtime, data, rowNum) {
		return new ctlTable(container, profile, runtime, data, rowNum);
	},

	ctlTable = function(container, profile, runtime, data, rowNum) {
		var a = this;
		a.id = profile.cId + (rowNum == undefined? '' : ('-' + rowNum));
		a.type = "TABLE";
		a.disabled = false;
		a.instance = runtime.instance;
		a.container = container;
		a.runtime = runtime;
		a.path = runtime.namespace + '.' + a.id;
		a.profile = profile;
		a.objProp = profile.ot || {};
		a.custProp = profile.o2 || {};
		a.xitemRow = rowNum;
		a.xitemData = data;
		a.resetCkb = [];
		a.changeCalls = [];
		a.dblclickCalls = [];
		// console.log(a);
		a.translater = {};
		a.radios = {};
		a.parentDisabled = a.disabled = false;
		a.attributes = {};
		a.flagCols = 0;

		var q = ctlStyle(a), style = q.style, outerStyle = q.outerStyle, innerStyle = q.innerStyle, clazz = q.clazz, tableHeight;
		a.dom = a.box = $('<div data-type="' + a.type + '" data-path="' + a.path + '" class="' + clazz.join(' ') + '" style="' + getStyles(style, outerStyle, innerStyle) + '" />').appendTo(container);
		if (parseInt(a.dom.css('flex-grow'))) {
			// 用于处理弹性布局
			if (a.dom.parent().css('flex-direction') == 'column')
				a.dom.css('height', 'auto');
			else
				a.dom.css('width', 'auto');
			//if (H5Utils.isChromeLegacy)
				a.box = $('<div class="wrapper" />').appendTo(a.dom);
			tableHeight = '100%';
		} else {
			tableHeight = getStyleAttr('height', style, outerStyle, innerStyle)
		}

		var columns = [];
		if (profile.cells) {
			// 绘制表头信息
			// cell信息中otherObj
			// {
			//  cr：xxx, 	当前列字体颜色
			//  c：xxx, 		描述
			//  t：1,		当前列类型(-1:需要翻译, 0:标准文本, 1:多选, 2:单选, 3:跟据这列值决定每一行颜色, 4:可换行的文本)
			//  k: xxx,		本地缓存主键
			//  s: xxx,		SQL缓存ID
			//  o: 0/1		是否能排序
			// }

			// 创建一个新的sql执行队列
			var tmpRuntime = {
				struct: a.runtime.struct,
				sqlQueue: {}
			}, colors, totalWidth = 0, flexColumn = false;
			$.each(profile.cells, function(i, cell){
				var coldis = cell.otherObj.c, title = coldis;
				//console.log(cell);

				if (cell.otherObj.t == -1) {
					// 需要翻译
					var c = cell.otherObj.k;
					if (c)
						c = runtime.struct.id + '.' + c;
					if (c && runtime.project.cache[c])
						a.translater['T'+ i] = runtime.project.cache[c];
					else {
						tmpRuntime.sqlQueue[cell.otherObj.s] = {
							structId : a.runtime.struct.id,
							params: {},
							callback: function(data) {
								if (data.count < 0) {
									$F.err('SQLExec - failed', 'DYN[' + a.runtime.struct.id + '] KEY[' + cell.otherObj.s + '], 控件[' + ctl.type + '@' + ctl.id + '][PARAMS: {}]');
									data = $.extend({
										columns: [],
										fields: []
									}, data);
								}

								var translationBean = {};
								$.each(data.fields, function(i2, rs){
									translationBean[rs[0]] = rs[1];
								});
								if (c)
									runtime.project.putCache(c, translationBean);
								a.translater['T' + i] = translationBean;
							}
						}
					}
				}

				if (cell.otherObj.t == 1) {
					if (title && title.startWith('#'))
						title = title.substring(1);
					else {
						coldis = $('<input type="checkbox" data-col="' + (parseInt(cell.col) - 1) + '" />')
							.on('click', function(e){
								e.stopPropagation();
								$F.process(function() {
									var ckb = $(e.target),
										col = parseInt(ckb.attr('data-col')),
										state = (ckb.prop('checked') ? 1 : 0),
										data = a.wisTable.getData(),
										row,
										cd = {};
									$.each(data, function(i, rowData) {
										row = a.wisTable.getRow(i);
										if (! a.custProp.disnum || (row.length == 1 && row.is(':visible'))) {
											cd[i + ',' + col] = rowData[col] = state;
											a.wisTable.refresh(i, col + a.flagCols);
										}
									})
									a.instance.fireValue(a.profile.vV, a.runtime, {type:1, data:cd}, a);
									doCmd(a, 'P8', {
										CTRL: a,
										EVENT: {
											CHECKALL: true,
											GRIDCOL: col + 1,
											STATE: state
										}
									})
								})
							});
						title = '';
						//a.resetCkb.push($('<label/>').text(cell.otherObj.c || '').append(coldis));
						a.resetCkb.push(coldis);
					}
				} else if (cell.otherObj.t == 3) {
					a.rowColorCell = parseInt(cell.col) - 1;
				}

				var cw = parseInt(cell.row || 0);
				if (cw < 0)
					cw = 0;
				var column = {
					display : $('<span title="' + title + '" />').append(coldis),
					name : 'th_' + (i + 1),
					width : Math.max(cw / 15, 0),
					align : (cell.type == 2 ? 'right' : (cell.type == 1 ? 'center' : 'left')),
					resizable: true,
					sortable : cell.otherObj.o,
					filterable: cell.otherObj.filter,
					wrapable : (cell.otherObj.t == 4),
					flex: (cell.otherObj.freeCol ? true:false),
					defCol: i,
					realCol: parseInt(cell.col) - 1,
					colName: (cell.otherObj.t == 1 ? '多选' : (cell.otherObj.t == 2? '单选' : title))
				};
				if (! column.width)
					column.forbidden = true;

				if (cell.otherObj.cr) {
					colors = cell.otherObj.cr.split(',');
					column.color = '#' + colors[0];
					if (colors.length > 2)
						column.background = '#' + colors[1];
				}
				columns.push(column);
				totalWidth += column.width;

				if (perz && perz.column && perz.column.contains(i)) {
					// 该列被权限设置屏蔽
					column.hide = true;
				}
			});
			a.instance.sqlexec(tmpRuntime);
		}

		if (a.objProp.wb) {
			// 按百分比部署表格
			if ((! perz || perz.rm) && a.custProp.rmcmd)
				totalWidth += 27;
			if ((! perz || perz.vi) && a.custProp.vicmd)
				totalWidth += 27;
			if (! a.custProp.hideline)
				totalWidth += 28;
			$.each(columns, function(i, v) {
				if (v.width)
					v.pw = v.width * 100 / totalWidth;
			})
		} else {
			// 获取本地个性化存储的数据
			var orders = localStorage.getItem(a.runtime.struct.id + '.' + a.id);
			if (orders) {
				orders = JSON.parse(orders);
				var getColumn = function(unit) {
					var c;
					for(var i=0; i<columns.length; i++) {
						c = columns[i];
						if (c.name == unit.n) {
							if (! unit.v)
								c.hide = true;
							columns.splice(i, 1);
							return c;
						}
					}
					return null;
				}
				var resort = [], one;
				$.each(orders, function(i, v) {
					one = getColumn(v);
					if (one)
						resort.push(one);
				})
				columns = resort.concat(columns);
			}
		}

		// 创建编辑与删除按钮列
		var perz = getPowerPersenalize(runtime, a.id);
		if (! perz || ! perz.vi) {
			if (a.custProp.vicmd) {
				columns.unshift({
					display: '',
					name: 'th_edit_flag',
					index: a.flagCols,
					width : 26,
					align: 'center',
					sortable: false,
					flag: 1
				});
				a.flagCols ++;
			}
		}
		if (! perz || perz.rm) {
			if (a.custProp.rmcmd) {
				columns.unshift({
					display: '',
					name: 'th_remove_flag',
					index: a.flagCols,
					width : 26,
					align: 'center',
					sortable: false,
					flag: 2
				});
				a.flagCols ++;
			}
		}

		if (columns.length > 0) {
			var selectCallback = function(data, row, e) {
				// col为表格中定义的真实数据的列下标
				// 遍历表格行变动时绑定的各个变量
				for(var key in a.objProp.ls) {
					var nv, property = a.instance.getProperty(key, runtime);
					if (! property)
						return $F.err('Ctls - Table', '变量未定义：' + key);
					var tmpIndex = a.objProp.ls[key]; // 变量对应的列号
					if (tmpIndex == -99){
						// 值为当前行号
						if (row == -1)
							nv = -1;
						else
							nv = row + 1;
					}else{
						// 值为单元格数据
						if (row == -1)
							nv = a.instance.getDefaultValue(property.VT, '');
						else
							nv = a.instance.getDefaultValue(property.VT, data[tmpIndex-1]);
					}
					a.instance.fireValue(key, runtime, {type:0,data:nv}, a);
				}
				$.each(a.changeCalls, function(){
					this(e, {
							GRIDROW: row + 1,
							ROWDATA: data
						});
				})
			}

			a.wisTable = $('<table />').appendTo(a.box).wisTable({
				debug: $E.debug,
				lang: $E.lang,
				height: tableHeight,
				border: (a.custProp.nl ? false : true),
				columns: columns,
				percentSplit: a.objProp.wb,
				cookie: (a.objProp.ck ? ('wistable.' + runtime.struct.id + '.' + a.id):''),
				sortable: a.custProp.sortable,
				dynamicLines: (a.custProp.disnum || 0),
				tabIndex: 0,
				lockCols: a.flagCols,
				hideLine: a.custProp.hideline,
				hideColumnMenu: a.custProp.hidecmenu,
				onCreateRow: function(tr, row, data) {
					if (a.rowColorCell !== undefined) {
						var cellData = data[a.rowColorCell];
						if (cellData) {
							var cs = cellData.split('||');
							if (cs[0])
								tr.css({
									background : cs[0]
								});
							if (cs.length > 1) {
								tr.css({
									color : cs[1]
								})
							}
						}
					}
				},
				plains: function(data, row, col) {
					if (col < 0)
						return '';

					var column = columns[col],
						cellData = data[column.realCol],
						cellInfo = profile.cells[column.defCol];

					if (column.flag == 1 || column.flag == 2)
						return '';
					if (cellInfo === undefined)
						return '';

					// 浏览表格的单元格属性类型
					// 1: 多选选项
					// 2: 单选选项
					// 3: 根据列值决定行颜色
					// 5: link（触发值变动）
					if (cellInfo.otherObj.t == 1 || cellInfo.otherObj.t == 2 || cellInfo.otherObj.t == 3) {
						return cellData;
					} else if (cellInfo.otherObj.t == 5) {
						// 链接
						var linkStr = cellInfo.otherObj.LK;
						if (linkStr) {
							var cs = linkStr.split('#');
							if (cs.length > 1)
								linkStr = cs[0];
						}
						return linkStr;
					} else if (cellInfo.otherObj.t == 6) {
						// 公式
						return CtlUtils.expression(cellData, cellInfo.otherObj.e, a.runtime);
					}

					// 对需要翻译的字段进行翻译
					if (a.translater['T' + column.defCol])
						cellData = a.translater['T' + column.defCol][cellData];

					if (cellData == undefined || cellData === '')
						return '';
					else {
						if ($.type(cellData) == 'object') {
							// console.log(cellData)
							// return cellData;
							if (cellData.html)
								return $(cellData.html).text();
							else
								return cellData.toString();
						} else
							return cellData;
					}
				},
				models: function(data, row, col, tr) {
					var column = columns[col],
						cellData = data[column.realCol],
						cellInfo = profile.cells[column.defCol];

					if (column.flag == 1 || column.flag == 2) {
						var tip = (column.flag == 1 ? $F.lang('message.edit') : $F.lang('message.remove')),
							ico = (column.flag == 1 ? 'edit' : 'trash-alt'),
							cmd = (column.flag == 1 ? a.custProp.vicmd : a.custProp.rmcmd),
							link = $('<a title="' + tip + '" class="dyn_link dyn_er_flag"><i class="' + $F.fas(ico) + '" /></a>');
						link.data('entity', data).on('click', function(e) {
							e.preventDefault();
							var t = $(e.currentTarget), _r = parseInt(tr.attr('data-row'));
							setTimeout(function(){
								a.instance.doCmd('P' + cmd, {
									CTRL: a,
									EVENT: {
										GRIDROW: _r + 1,
										ROWDATA: t.data('entity')
									}
								}, a.runtime, a.id)
							}, 10)
						})
						return link;
					}

					//console.log(cellInfo);
					//console.log(column)
					if (cellInfo === undefined)
						return '';

					// 浏览表格的单元格属性类型
					// 1: 多选选项
					// 2: 单选选项
					// 3: 根据列值决定行颜色
					// 5: link（触发值变动）

					// 多选选项
					if (cellInfo.otherObj.t == 1) {
						var checkbox = $('<input type="checkbox" class="js_ckb_'+ col +'" name="' + a.path.replaceAll('\\.', '_') + '_ckb_' + column.realCol + '" data-c="' + column.realCol + '" />')
							.click(function(e){
								var $t = $(this), _r = parseInt(tr.attr('data-row')), _c = parseInt($t.attr('data-c'));
								var cd = {};
								cd[_r + ',' + _c] = (this.checked? 1:0);
								a.instance.fireValue(profile.vV, runtime, {
									type: 1,
									data: cd
								}, a);

								// 通知列上绑定的属性对象
								for(var key in a.objProp.ls) {
									if (a.objProp.ls[key] == _c + 1) {
										a.instance.fireValue(key, runtime, {type:0, data:a.value[_r][_c]}, a);
									}
								}
								doCmd(a, 'P8', {
									CTRL: a,
									EVENT: {
										GRIDROW: _r + 1,
										GRIDCOL: _c + 1,
										ROWDATA: a.value[_r],
										COLDATA: a.value[_r][_c]
									}
								})
							});
						checkbox.prop("checked", cellData? true : false);
						return checkbox; //$('<label />').append(checkbox);
					} else if (cellInfo.otherObj.t == 2) {
						// 单选选项
						var radio = $('<input type="radio" class="js_rb_'+ col +'" name="' + a.id + '_rb_' + column.realCol + '" data-c="' + column.realCol + '" /><label />').click(function(e){
							var $t = $(this), _r = parseInt(tr.attr('data-row')), _c = parseInt($t.attr('data-c'));
							if (a.radios && (a.radios['C' + _c] == _r))
								return;

							var cd = {};
							cd[_r + ',' + _c] = 1;
							a.instance.fireValue(profile.vV, runtime, {
								type: 1,
								data: cd
							}, a);

							// 清除已有的单选选项
							if (a.radios && (a.radios['C' + _c] != undefined)){
								cd[a.radios['C' + _c] + ',' + _c] = 0;
								a.instance.fireValue(profile.vV, runtime, {
									type: 1,
									data: cd
								}, a);
							}
							a.radios['C' + _c] = _r;

							// 通知列上绑定的属性对象
							for(var key in a.objProp.ls) {
								if (a.objProp.ls[key] == (_c+1)) {
									a.instance.fireValue(key, runtime, {type:0, data:a.value[_r][_c]}, a);
								}
							}
						});
						if (cellData) {
							if (a.radios['C' + col] == undefined) {
								radio.prop("checked", true);
								a.radios['C' + col] = row;
							} else {
								data[column.realCol] = 0;
							}
						}
						return radio;
					} else if (cellInfo.otherObj.t == 3) {
						// 根据列值决定行颜色
						if (cellData) {
							var cs = cellData.split('||');
							if (cs[0])
								tr.css({
									background: cs[0]
								});
							if (cs.length > 1) {
								tr.css({
									color: cs[1]
								})
							}
						}
					} else if (cellInfo.otherObj.t == 5) {
						// 链接
						var linkStr = cellInfo.otherObj.LK, linkCmd, xss=Helper.filter(cellData);
						if (linkStr) {
							var cs = linkStr.split('#');
							if (cs.length > 1) {
								linkStr = cs[0];
								linkCmd = cs[1];
							}
						}
						var link = $('<a href="javascript:;" class="dyn_link" data-c="' + column.realCol + '">' + (linkStr || xss) + '</a>')
							.click(function(e){
								e.preventDefault();
								e.stopPropagation();
								var $t = $(this), _r = parseInt(tr.attr('data-row')), _c = parseInt($t.attr('data-c'));
								if (linkCmd) {
									a.instance.doCmd('P' + linkCmd, {
										CTRL: a,
										EVENT: {
											GRIDROW: _r + 1,
											GRIDCOL: _c + 1,
											ROWDATA: a.value[_r],
											COLDATA: a.value[_r][_c]
										}
									}, runtime, a.id);
								} else {
									doCmd(a, 'P8', {
										CTRL: a,
										EVENT: {
											GRIDROW: _r + 1,
											GRIDCOL: _c + 1,
											ROWDATA: a.value[_r],
											COLDATA: a.value[_r][_c]
										}
									})
								}
							});
						return link;
					} else if (cellInfo.otherObj.t == 6) {
						// 公式
						return CtlUtils.expression(cellData, cellInfo.otherObj.e, a.runtime);
					}

					// 对需要翻译的字段进行翻译
					if (a.translater['T' + column.defCol])
						cellData = a.translater['T' + column.defCol][cellData];

					if (cellData == undefined || cellData === '')
						return '';
					else {
						if ($.type(cellData) == 'object') {
							// console.log(cellData)
							// return cellData;
							if (cellData.html)
								return $(cellData.html);
							else {
//									if ($.type(cellData) == 'string' && cellData == '1900-01-01 00:00:00')
//										return '';
//									else
									return cellData;
							}
						} else
							return $('<span />').text(cellData).attr('title', cellData);
					}
				},
				visible: function(data) {
					// -99 为表头
					return (data['flag'] !== -99);
				},
				onSort: function(col, columnName, direct) {
					col = columns[col].realCol;
					if (a.custProp.sortcmd) {
						a.instance.doCmd('P' + a.custProp.sortcmd, {
							EVENT: {
								COL : col + 1,
								COLNAME : columnName,
								DIRECT : direct
							}
						}, runtime, a.id);
					} else {
						$F.process(function(){
							var newData = $.extend([], a.wisTable.data.sort(function(a, b){
								if (a[col] > b[col])
									return (direct == 'asc')?1:-1;
								else if (a[col] < b[col])
									return (direct == 'asc')?-1:1;
								else
									return 0;
							}));
							// 将选择结果通知其他控件监听者
							a.instance.fireValue(profile.vV, runtime, {type: 0, data: newData});
						}, 'Sorting...')
					}
				},
				onPersonalize: function(data) {
					// console.log(data);
					if (data.type == 'orders' || data.type == 'hidden') {
						localStorage.setItem(a.runtime.struct.id + '.' + a.id, JSON.stringify(data.value));
						// CmdUtils.setLocalValue(a.runtime, a.id + '.orders', JSON.stringify(data.value))
					}
				},
				onDblClick : function(data, row, e) {
					$F.process(function() {
						$.each(a.dblclickCalls, function() {
							this(e, {
								GRIDROW: row + 1,
								ROWDATA: data
							})
						})
					})
				},
				onSelected : function(data, row, e) {
					selectCallback(data, row, e);
				},
				onUnselected : function() {
					selectCallback([], -1);
				},
				onMove : function(cur, tar, data) {
					var cs = {};
					cs[cur] = data[tar];
					cs[tar] = data[cur];
					a.instance.fireValue(a.profile.vV, a.runtime, {
						type : 1,
						data : cs
					}, a);
				}
			});
			if (a.custProp.filtercmd) {
				a.wisTable.options.onFilter = function(filterArray) {
					a.instance.doCmd('P' + a.custProp.filtercmd, {
						EVENT: filterArray
					}, runtime, a.id);
					//console.info(filterArray);
				}
			}
		}
		a.dom.append('<div class="eliteDisabledMasker"/>');

		/*
		var uniqueId = $F.randomString(16);
		a.dom.attr('id', uniqueId);
		var cmitems = {
			'copy' : {
				name : '复制行数据',
				icon : "copy"
			},
			'sep' : '-----------',
			'export' : {
				name: '导出',
				icon: 'file-export'
			}
		};
		$.contextMenu({
			selector : ('#' + uniqueId + ' tr.wistable_row>td'),
			iconStyle : 'fa',
			onShow : function(e) {
				$(e).click();
			},
			callback : function(key, options, target) {
				if (key == 'copy') {
					var row = target.parent().attr('data-row');
					var data = a.wisTable.getData(),
						rowdata = data[row];
					if (rowdata) {
						H5Utils.clip(rowdata, function() {
							$F.info(i18n.sys.clipSuccess)
						})
					}
				} else if (key == 'export') {
					a.exportExcel('Untitle');
				}
			},
			items : cmitems,
			appendTo : container
		})
		*/
		if (a.custProp.s_state)
			a.state(a.custProp.s_state);
		makeValueAndState(a, data, rowNum);
		return a;
	};

	ctlTable.prototype = {
		state : function(e) {
			if (e == undefined)
				return this._state;
			else {
				this._state = e;
				if (e == 1)
					this.dom.hide();
				else {
					this.dom.show();
					this.disable(e == 2);
				}
			}
		},
		disable: function(e, byParent) {
			if (byParent) {
				this.dom.toggleClass('disabled', e || this.disabled);
				this.parentDisabled = e
			} else {
				this.dom.toggleClass('disabled', e || this.parentDisabled);
				this.disabled = e;
			}
		},

		val : function(t) {
			var a = this
			if (t == undefined)
				return a.value || [];
			else {
				if (a.objProp.a) {
					// 首行数据变表头
					if (t.length > 0) {
						$.each(t[0], function(i, v){
							a.wisTable.setColumnLabel(i + a.flagCols, v);
						})
					}
					a.value = [];
					$.each(t, function(i, v){
						if (i > 0)
							a.value.push(v)
					})
				} else
					a.value = t;

				if (a.wisTable) {
					a.radios = {};
					a.wisTable.setData(a.value);
				}
				// 刷新checkbox全选状态
				$.each(a.resetCkb, function() {
					$(this).prop('checked', false);
				})
				if (a.custProp.tipped && window.Tipped)
					Tipped.create($('span', a.wisTable.bDiv), { position: 'topleft' })
				return a;
			}
		},
		evt : function(e) {
			var a = this;
			if (e == undefined) {
				return {
					type: 0,
					data: a.val()
				}
			} else {
				if (a.scrollThread)
					clearInterval(a.scrollThread);

				if (e.type) {
					if (a.wisTable) {
						var array = [], ks, row;
						for(var key in e.data) {
							ks = key.split(',');
							if (ks.length == 1) {
								if (ks[0] == '-1') {
									// 整表更新
									a.wisTable.setData(a.wisTable.getData(), 2);
								} else {
									// 整行更新
									// a.wisTable.getData()[parseInt(ks[0])] = e.data[key];
									a.wisTable.refreshRow(parseInt(ks[0]))
								}
							} else {
								// console.log('TABLE[' + a.id + '] refresh cell:' + ks[0] + ',' + ks[1] + ' = ' + e.data[key])
								a.wisTable.refresh(parseInt(ks[0]), parseInt(ks[1]) + a.flagCols);
							}
						}
					}
					return a;
				} else
					return a.val(e.data);
			}
		},

		bind : function(e, callback) {
			if (e == 'dblclick')
				this.dblclickCalls.push(callback);
			else if (e == 'change')
				this.changeCalls.push(callback);
		},

		triggerChange : function(e) {
			$.each(this.changeCalls, function() {
				this();
			})
		},

		nextRow : function() {
			this.wisTable.selectNext();
		},

		prevRow : function() {
			this.wisTable.selectPrev();
		},

		jumpRow : function(row) {
			this.wisTable.jumpRow(row - 1);
		},

		/**
		 * 全选某列
		 * @param col
		 * @param state
		 * @returns
		 */
		scopeCheck : function(col, state) {
			var a = this;
			if (a.wisTable) {
				if (col < 0)
					return $F.err('Ctls - Table', '全选操作的列号不能小于1');
				if (a.profile.cells[col].otherObj.t != 1)
					return $F.err('Ctls - Table', '列[' + (col + 1) + ']不是多选项，不可进行全选操作');
				var ckbs = $('.js_ckb_' + col, a.wisTable.table);
				$.each(ckbs, function(i, v){
					var $ckb = $(v);
					if ($ckb[0].checked != state)
						$ckb.trigger('click');
				})
			}
		},

		/**
		 * 上移某行
		 * @param row
		 * @returns {Boolean}
		 */
		rowMoveUp : function(row) {
			if (this.wisTable) {
				if (row === undefined)
					row = this.wisTable.getSelectedIndex();
				else
					row = parseInt(row) - 1;

				if (row < 1)
					return false;

				if (this.wisTable.moveUp(row)) {
					return true;
				} else {
					//console.log('TABLE[' + this.id +  '] move up faild')
					return false;
				}
			} else
				return false;
		},

		/**
		 * 下移某行
		 * @param row
		 * @returns {Boolean}
		 */
		rowMoveDown : function(row) {
			if (this.wisTable) {
				if (row === undefined)
					row = this.wisTable.getSelectedIndex();
				else
					row = parseInt(row) - 1;

				if (row + 1 >= this.wisTable.getData().length)
					return false;

				if (this.wisTable.moveDown(row)) {
					return true;
				} else {
					//console.log('TABLE[' + this.id +  '] move down faild')
					return false;
				}
			} else
				return false;
		},

		columnLabel : function(col, title) {
			this.wisTable.setColumnLabel(col - 1 + this.flagCols, title);
		},

		/**
		 * 设置列宽
		 * @param col
		 * @param width
		 */
		cellWidth : function(col, width) {
			this.wisTable.setCellWidth(col - 1 + this.flagCols, width);
		},
		setCellWidth : function(col, width) {
			this.cellWidth(col, width);
		},

		/**
		 * 重新排列表格的列顺序
		 * @param orders
		 */
		cellsOrder : function(orders) {
			this.wisTable.setCellsOrder(orders);
		},

		sort : function(col, direct) {
			this.wisTable.sortColumn(col - 1 + this.flagCols, direct);
		},

		/**
		 * 为一个空白的表格控件创建UI
		 * @param columns {array} 表头数组
		 *
		 * 	column = {
		 *		display: {string} 单元格标签，用于显示,
		 *		name: {string} 单元格名称，保留属性，不重复即可,
		 *		width: {integer} 单元格宽度，-1为该列不显示，0为自动宽度,
		 *		align: {integer} 单元格对齐 0='left', 1='center', 2='right',
		 *		sortable: {boolean} 单元格是否可排序
		 *		color: {string} 单元格颜色，例如#000000
		 * 	}
		 *
		 * @param modelsCallback {callback} 数据渲染回调方法, function(data, row, col)
		 * @param selectedCallback {callback} 点选行后的回调方法, function(data, row)
		 * @param dblclickCallback {callback} 双击行后的回调方法, function(data, row)
		 * @param data {array} 表格数据（二维数组）
		 */
		build : function(columns, modelsCallback, selectedCallback, dblclickCallback, data) {
            var a = this;
			if (a.wisTable) {
				return $F.alert('当前表格控件对象已经被创建过UI，不可重复。');
			}

			a.wisTable = $('<table />').appendTo(a.dom).wisTable({
				debug: $E.debug,
				columns: columns,
				models : modelsCallback,
				onSelected: selectedCallback,
				onDblClick: dblclickCallback
			}).setData(data);
		},

		/**
		 * 向上滚动表格
		 */
		scrollUp : function(second) {
			var a = this;
			if (a.scrollThread)
				clearInterval(a.scrollThread);
			if (second > 0) {
				a.scrollThread = setInterval(function() {
					//console.log('Ctls - table', '调度表格自动向上滚屏: ' + a.id)
					if (a.wisTable.bDiv[0].scrollHeight > a.wisTable.bDiv[0].clientHeight)
						a.wisTable.scrollUp(500);
				}, second * 1000);
			}
		},

		/**
		 * 向下滚动表格
		 */
		scrollDown: function(second) {
			var a = this;
			if (a.scrollThread)
				clearInterval(a.scrollThread);
			if (second > 0) {
				a.scrollThread = setInterval(function(){
					// console.log('Ctls - table', '调度表格自动向下滚屏: ' + a.id + ' every ' + secends + ' \'s');
					if (a.wisTable.bDiv[0].scrollHeight > a.wisTable.bDiv[0].clientHeight)
						a.wisTable.scrollDown(500);
				}, second * 1000);
			}
		},

		setStyle : function(cssStyle) {
			this.dom.css(cssStyle);
		},

		driftLayer : function(layer) {
			var row = this.wisTable.getSelectedDom();
			if (row.length == 0)
				return $F.err('Ctls - table', '当前没有选中的行'), 0;
			var owner = $('td.cur', row);
			layer.drift(owner.offset().top, owner.offset().left, owner.offset().top + owner.outerHeight(), owner.offset().left + owner.outerWidth());
		},

		redraw : function() {
			this.wisTable.redraw();
		},

		hidden : function(columns) {
			this.wisTable.hidden(columns);
		},

		bindProperty: function(propertyName) {
			// 绑定了变量的控件，值改变时触发消息通知给实例
			var a = this;
			propertyName = propertyName.toLowerCase();
			a.bind('change', function(e){
				a.instance.fireValue(propertyName, a.runtime, a.evt(), a);
			});

			// 绑定值消息，当实例改变时，控件同步更新
			a.val(a.instance.getValue(propertyName, a.runtime));
			a.instance.bindValue(propertyName, a, function(e) {
				a.evt(e);
			});
		},

		exportExcel : function(title) {
			var a = this, excel = [], head = [], infos = [], columns = [];
			var lock = {
				colSplit: 0,
				rowSplit: 2,
				leftmostColumn: 0,
				topRow: 2
			};
			$.each(a.profile.cells, function(i, cell){
				if (i == 0) {
					head.push({
						value: title,
						height: 30,
						align: 2,
						colspan: a.profile.cells.length,
						rowspan: 1,
						fontFamily: 'Microsoft Yahei',
						fontBold: true,
						fontSize: 18
					})
				} else {
					head.push({
						value:'',
						occupied: true,
						align: 2,
						colpos: 1,
						rowpos: i + 1
					})
				}
				columns.push({
					value: (cell.otherObj ? cell.otherObj.c : ''),
					fontFamily: 'Microsoft Yahei',
					fontBold: true,
					fontSize: 10,
					border: true,
					bgColor: '#e7f5fb',
					grid: true
				})
				infos.push({
					align: cell.type + 1,
					width: cell.row / 15,
					visible: (cell.row ? true : false)
				})
			})
			if (title)
				excel.push(head);
			else
				lock.topRow = 1;

			excel.push(columns);

			var getValue = function(col, data) {
				// 浏览表格的单元格属性类型
				// 1: 多选选项
				// 2: 单选选项
				// 3: 根据列值决定行颜色
				// 5: link（触发值变动）
				var cellType = a.profile.cells[col].otherObj.t;
				if (cellType == 1) {
					// 多选选项
					return data;
				} else if (cellType == 2) {
					// 单选选项
					return data;
				} else if (cellType == 3) {
					// 行颜色
					return data;
				} else if (cellType == 5) {
					// 链接
					return data;
				} else if (cellType == 6) {
					// 公式
					if (data == undefined || data == null)
						return ''

					var formula = a.profile.cells[col].otherObj.e;
					if (formula) {
						// formula = formula.toUpperCase();
						var nf = (/^N\((.*)\)/gi).exec(formula),
							sf = (/^S\((.*)\)/gi).exec(formula),
							df = (/^D\((.*)\)/gi).exec(formula);
						if (nf) {
							// 数字格式化
							return $F.formatNumber(data, nf[1]);
						} else if (sf) {
							if ($.type(data) !== 'string')
								return $F.err('Ctls - Table', '非字符串不可进行字符串格式化'), '';
							// 字符串格式化
							var xss=Helper.filter(data);
							return $F.formatString(xss, sf[1]);
						} else if (df) {
							// 日期格式化
							if (! data)
								return ''

							if ($.type(data) == 'number') {
								var date = new Date(data);
								return date.format(df[1]);
							} else if ($.type(data) == 'string') {
								var format, st = data.split(' ');
								if (st.length < 2) {
									var subt = st[0].split(':');
									if (subt.length > 1) {
										// 字符串为时间
										if (subt.length == 2)
											format = "H:i";
										else
											format = "H:i:s";
									}  else {
										// 字符串为日期
										format = "Y-m-d";
									}
								} else {
									// 字符串为完整日期时间
									var subt = data.trim().split(':');
									if (subt.length > 1) {
										// 字符串为时间
										if (subt.length == 2)
											format = "Y-m-d H:i";
										else
											format = "Y-m-d H:i:s";
									}  else {
										// 字符串为日期
										format = "Y-m-d H";
									}
								}
								// console.log(data+ ' parse to "' + format + '"')
								var date = Date.parseDate(data, format);
								if (! date) {
									$F.err('转换日期对象失败：' + data);
									return '';
								}
								//console.log(date);
								if (date.getFullYear() == 1900)
									return '';

								return date.format(df[1]);
							} else {
								$F.err('Ctls - Table', '不合法的日期格式化对象:' + $.type(data));
								return ''
							}
						} else {
							if (data == undefined)
								return '';

							if (formula.toLowerCase() == 'totime') {
								var seconds = parseInt(data);// 秒
								var minites = 0;// 分
								var hours = 0;// 小时

								minites = parseInt(seconds / 60);
								seconds = parseInt(seconds % 60);	// 余秒
								hours = parseInt(minites / 60);
								minites = parseInt(minites % 60);	// 余分

								var hoursStr = hours > 9 ? hours : ('0' + hours);
								var minitesStr = minites > 9 ? minites : ('0' + minites);
								var seconsStr = seconds > 9 ? seconds : ('0' + seconds);
								return hoursStr + ':' + minitesStr + ':' + seconsStr;
							} else if (formula.toLowerCase() == 'mask') {
								var mask = a.instance.project.getParam('TELWLD');
								if (mask) {
									var cs = mask.split(','), start = parseInt(cs[0]), end, t = data;
									t = t + '';
									var visible = t.substring(0, start-1);
									if (t.length >= start && start > 0) {
										if (cs.length == 1) {
											var mask = '';
											for(var i=0; i<t.length - start + 1; i ++) {
												if (mask.length < 6)
													mask += '*'
											}
											return (visible + mask);
										} else {
											end = parseInt(cs[1]);
											var mask = '', end = Math.min(end, t.length - start + 1);
											for(var i=0; i<end; i ++) {
												if (mask.length < 6)
													mask += '*'
											}
											var after = (t.length >= (start - 1 + end)) ? t.substring(start - 1 + end) : '';
											return (visible + mask + after);
										}
									}
								}
								return
							} else
								return $F.err('Ctls - Table', '不能识别的公式： ' + formula), '';
						}
					}
					return data;
				}

				// 对需要翻译的字段进行翻译
				if (a.translater['T' + col])
					data = a.translater['T' + col][data];

				if (data == undefined)
					return '';
				else
					return data;
			}

			var profile = a.profile;
			$.each(a.wisTable.getData(), function(i, data) {
				var cs = [], bg, fc;
				$.each(data, function(k, v) {
					if (profile.cells.length <= k)
						return;

					cs.push({
						value : getValue(k, v),
						border: true,
						grid: true
					})
					// 根据列值决定行颜色
					if (profile.cells[k].otherObj.t == 3 && v[k]) {
						var colors = v[k].split('||');
						if (colors[0])
							bg = colors[0]
						if (colors.length > 1)
							fc = colors[1]
					}
				})
				if (bg || fc) {
					$.each(cs, function(k, v) {
						if (! v)
							return;

						if (bg)
							v.bgColor = bg;
						if (fc)
							v.color = fc;
					})
				}
				excel.push(cs);
			})

			var busyId = $F.busyShow();
			Ajax.post({
				url: $E.url + '/reporter/export_',
				contentType: 'json',
				data: JSON.stringify({
					token: a.instance.project.token,
					digest: a.instance.project.digest,
					dbPool: '',
					id: Guid.raw(),
					name: title,
					data: excel,
					infos: infos,
					lock: lock,
				}),
				digest: a.instance.project.digest,
				success: function(data) {
					// console.log(data);
					if (data.code > 0) {
						var url = $E.url + '/fs/get?d=true&' + encodeURI('file=' + data.value + '&as=' + title + '.xlsx');
						window.open(url, '_blank');
					} else
						$F.alert(data.message);
				},
				always: function() {
					$F.busyHide(busyId);
				}
			})
		},

		/**
		 * 清空所有过滤器
		 * @param columns (option) 可以不传递，表示清除所有过滤器，也可以传递单个列号，多个列号用数组方式传递
		 */
		clearFilter : function(columns) {
			//$('.wistable_head_flyer .filter .clean_btn', this.dom).trigger('click');
			var fn = this.wisTable;
			if (columns) { //清除给定列的
				if (!$.isArray(columns)) {
					columns = [columns];
				}
				$.each(columns, function(index, col) {
					var th = fn.getHead(col);
					if ($.isFunction(fn.options.onFilter)) {
						$('th', fn.hDiv).each(function(i, v) {
							if (v == th[0]) {
								th.data('filterKey', '');
								th.removeClass('filter');
							}
						})
						fn.filterCallback();
					} else {
						$('th', fn.hDiv).each(function(i, v) {
							if (v == th[0]) {
								th.data('filterKey', '');
								th.removeClass('filter');
								fn.filter('', i);
							}
						})
					}
				});
				fn.grid.trigger('click');
			} else { //清除所有filter
				fn.clearFilter();
				fn.grid.trigger('click');
			}
		},

		destroy: function() {
			var a = this;
			if (a.scrollThread)
				clearInterval(a.scrollThread);
			if (a.wisTable && $.isFunction(a.wisTable.destroy)) {
				a.wisTable.destroy();
			}
		},
		getItem: function(e) {
			return this.attributes[e];
		},
		setItem: function(e, v) {
			this.attributes[e] = v;
			return this;
		}
	};

	/*
	 * 动态页面组件：Table
	 */
	var cTable2 = function(container, profile, runtime, data, rowNum) {
		return new ctlTable2(container, profile, runtime, data, rowNum);
	},

	ctlTable2 = function(container, profile, runtime, data, rowNum) {
		var a = this;
		a.id = profile.cId + (rowNum == undefined? '' : ('-' + rowNum));
		a.type = "TABLE2";
		a.disabled = false;
		a.instance = runtime.instance;
		a.container = container;
		a.runtime = runtime;
		a.path = runtime.namespace + '.' + a.id;
		a.profile = profile;
		a.objProp = profile.ot || {};
		a.custProp = profile.o2 || {};
		a.xitemRow = rowNum;
		a.flagCols = 0;

		if (data) {
			// 嵌套子表格形式
			if (profile.rl) {
				if (data[profile.rl - 1] == undefined) {
					data[profile.rl - 1] = [];
				}
			}
		}
		a.changeCalls = [];
		a.dblclickCalls = [];
		a.parentDisabled = a.disabled = false;
		a.attributes = {};
		//console.log(a);

		var q = ctlStyle(a), style = q.style, outerStyle = q.outerStyle, innerStyle = q.innerStyle, clazz = q.clazz, tableHeight;
		var uniqueId = $F.randomString(16);
		a.dom = a.box = $('<div id="' + uniqueId + '" data-type="' + a.type + '" data-path="' + a.path + '" class="' + clazz.join(' ') + '" style="' + getStyles(style, outerStyle, innerStyle) + '" />').appendTo(container);
		if (parseInt(a.dom.css('flex-grow'))) {
			// 用于处理弹性布局
			if (a.dom.parent().css('flex-direction') == 'column')
				a.dom.css('height', 'auto');
			else
				a.dom.css('width', 'auto');
			//if (H5Utils.isChromeLegacy)
				a.box = $('<div class="wrapper" style="overflow:auto" />').appendTo(a.dom);
			tableHeight = '100%';
		} else {
			tableHeight = getStyleAttr('height', style, outerStyle, innerStyle)
		}
		a.dom.bind('focus', function(){
			//console.log(a.profile.vV);
		})

		// 整理columns
		a.columns = [];
		a.translater = {};
		a.makeColumns();

		a.wisTable = $('<table />').appendTo(a.box).wisTable({
			debug: $E.debug,
			lang: $E.lang,
			height: tableHeight,
			columns: a.columns,
			sortable: true,
			//dynamicShow: true,
			cookie: a.objProp.ck ? ('wistable.' + runtime.struct.id + '.' + a.id):'',
			border: (a.custProp.nl? false : true),
			tabIndex: 0,
			onCreateRow: function(tr, row, data) {
				if (a.rowColorCell !== undefined) {
					var cellData = data[a.rowColorCell];
					if (cellData) {
						var cs = cellData.split('||');
						if (cs[0])
							tr.css({
								background : cs[0]
							});
						if (cs.length > 1) {
							tr.css({
								color : cs[1]
							})
						}
					}
				}
			},
			models: function(data, row, col, tr) {
				// console.log(col, a.columns);
				var column = a.columns[col],
					defCol = column.defCol, 	// profile中定义的cells信息列号
					realCol = column.realCol;	// data中对应的数据列号

				var listRow = a.objProp.ListRow[defCol], cellData = data[realCol], tra = a.translater['T' + defCol];
				// 对需要翻译的字段进行翻译
				if (tra) {
					//var old = cellData;
					if (a.multiEntity && a.multiEntity.contains(defCol)) {
						// 下拉多选值
						if ($.type(cellData) == 'string') {
							var cs = [];
							$.each(cellData.split(','), function(i, v) {
								if (tra[v] !== undefined)
									cs.push(tra[v]);
							})
							cellData = cs.join(',')
						} else
							cellData = tra[cellData];
					} else
						cellData = tra[cellData];
					// console.log(tra);
					// console.log('[' + realCol + '] ' + old + ' -> ' + cellData);
				}
				// console.log(data);
				// 修改 by Jet
				if (listRow.C == 12){
					//不规则单元格
					var mOneCellType = data[listRow.D1-1];
					if (mOneCellType == 5){
						var relSql = data[listRow.D2-1];
						if (relSql) {
							relSql = relSql.trim().toLowerCase();
							if (relSql != ""){
								if (a.translater['P' + relSql]){
									cellData = a.translater['P' + relSql][cellData];
								}else{
									var mTmpObj = runtime.project.cache[runtime.struct.id + ".PS#" + relSql];
									if (mTmpObj) {
										a.translater['P' + relSql] = mTmpObj;
										cellData = mTmpObj[cellData];
									}else{
										var mRs=$F.ajaxSync("JSGenerateServlet4",{
															token: runtime.project.token,
															dbPool: "",
		  							 						name:"Dyn.PublicSql.Get",
		  							 						pubKey:relSql
														}, runtime.project.digest);
    						   			if (mRs.code>0){
    										if (mRs.value.count>=0){
    											var translationBean={};
    											$.each(mRs.value.fields, function(i2, rs){
													translationBean[rs[0]] = rs[1];
												});
												runtime.project.putCache(runtime.struct.id + ".PS#"+relSql, translationBean);
												a.translater['P' + relSql] = translationBean;
    											cellData = translationBean[cellData];
    										}else{
    											console.error("动态SQL执行失败:"+listRow.D2+" Err:"+mRs.value.failedDesc);
    										}
    									}else{
    										console.error("动态SQL执行失败:"+listRow.D2+" Err:"+mRs.message);
    									}
									}
								}
							}else{
								console.error("动态SQL执行失败,动态SQL为空");
							}
						}else{
							console.error("动态SQL执行失败,动态SQL为空或未指定");
						}
					}else{
						//不改显示内容
					}
				} else if (listRow.C == 1) {
					// 单元为多选
					var checkbox = $('<input type="checkbox" class="js_ckb_' + col + '" name="' + a.path.replaceAll('\\.', '_') + '_ckb_' + col + '" data-col="' + realCol + '" />');
					checkbox.click(function(e){
						var $t = $(this), _r = parseInt(tr.attr('data-row')), _c = parseInt($t.attr('data-col'));
						var oldVal = data[_c];
						var cd = {};
						cd[_r + ',' + _c] = (this.checked? 1:0)
						if (profile.vV) {
							a.instance.fireValue(profile.vV, runtime, {
								type: 1,
								data: cd
							}, a);
						} else {
							data[_c] = (this.checked? 1:0);
						}
						// 设置行记录修改标志
						if(data['flag'] !== 2)
							data['flag'] = 1;

						// 调用命令组
						if (parseInt(listRow.Y)) {
							// 定义了命令组，需要触发
							// 单元格值变动时执行命令组: struct.CtlCmdList[10000+(命令组位于当前列+1)]
							var R = {
								CTRL : a,
								EVENT : {
									GRIDROW: _r + 1,
									GRIDCOL: _c + 1,
									ROWDATA: data,
									OLDVALUE: oldVal
								}
							}
							doCmd(a, 'P' + (10000 + defCol + 1), R);
							if (! R['REFRESH'])
								return;
							else if (R['REFRESH'] == 1) {
								a.wisTable.refresh(row);
							} else if (R['REFRESH'] == 2) {
								a.wisTable.refresh();
							}
						}
					});
					checkbox.prop("checked", parseInt(cellData));
					return $('<label />').append(checkbox);
				} else if (listRow.C == 9) {
					// 链接
					var link = $('<a href="javascript:;" class="dyn_link" data-col="' + realCol + '" />');
					if (listRow.LK) {
						link.html(listRow.LK)
					} else {
						link.text(data[realCol] || '...');
					}
					link.click(function(e){
						e.preventDefault();
						// 调用命令组
						if (parseInt(listRow.Y)) {
							// 定义了命令组，需要触发
							// 单元格值变动时执行命令组: struct.CtlCmdList[10000+(命令组位于当前列+1)]
							var $t = $(this), _r = parseInt(tr.attr('data-row')), _c = parseInt($t.attr('data-col'));
							var R = {
								CTRL : a,
								EVENT : {
									GRIDROW: _r + 1,
									GRIDCOL: _c + 1,
									ROWDATA: data,
									OLDVALUE: data[_c]
								}
							}
							doCmd(a, 'P' + (10000 + defCol + 1), R);
							if (! R['REFRESH'])
								return;
							else if (R['REFRESH'] == 1) {
								a.wisTable.refresh(row);
							} else if (R['REFRESH'] == 2) {
								a.wisTable.refresh();
							}
						}
					});
					return link;
				} else if (listRow.C == 13) {
					// 动态扩展列，内容为扩展字段绑定的交叉表第一行
					var rs = a.wisTable.getData();
					if (column.realCol == -1)
						column.realCol = getExtCol(rs[0], column.crossCol);
					if (column.realCol > -1) {
						//console.log('找到匹配的交叉列： ' + column.crossCol + ', col=' + column.realCol)
						cellData = data[column.realCol];
						if (column.editType == 5){
							var relSql = column.selectCol;
							if (relSql) {
								relSql = relSql.trim().toLowerCase();
								if (relSql != ""){
									if (a.translater['P' + relSql]){
										cellData = a.translater['P' + relSql][cellData];
									}else{
										var mTmpObj = runtime.project.cache["PS#" + relSql];
										if (mTmpObj) {
											a.translater['P' + relSql] = mTmpObj;
											cellData = mTmpObj[cellData];
										}else{
											var mRs=$F.ajaxSync("JSGenerateServlet4",{
																token: runtime.project.token,
																dbPool: "",
			  							 						 name:"Dyn.PublicSql.Get",
			  							 						 pubKey:relSql
															}, runtime.project.digest);
	    						   			if (mRs.code>0){
	    										if (mRs.value.count>=0){
	    											var translationBean={};
	    											$.each(mRs.value.fields, function(i2, rs){
														translationBean[rs[0]] = rs[1];
													});
													runtime.project.putCache("PS#"+relSql, translationBean);
													a.translater['P' + relSql] = translationBean;
	    											cellData = translationBean[cellData];
	    										}else{
	    											console.error("动态SQL执行失败:"+listRow.D2+" Err:"+mRs.value.failedDesc);
	    										}
	    									}else{
	    										console.error("动态SQL执行失败:"+listRow.D2+" Err:"+mRs.message);
	    									}
										}
									}
								}else{
									console.error("动态SQL执行失败,动态SQL为空");
								}
							}else{
								console.error("动态SQL执行失败,动态SQL为空或未指定");
							}
						}
					} else {
						if (rs.length > 0) {
							if (rs[0].length == 0) {
								// 交叉表无数据，造成0行字段没有静态列
								rs[0][a.staticCol + 1] = column.crossCol;
								column.realCol = a.staticCol + 1;
							} else {
								rs[0].push(column.crossCol);
								column.realCol = rs[0].length - 1;
							}
							// console.info(rs[0].join(', '))
							//console.log('交叉列取值匹配失败： ' + column.crossCol + ', 创建列=' + column.realCol)
						}
					}
					if (cellData == undefined ) {
						if (column.editType == 1)
							cellData = data[column.realCol] = 0;
						else
							cellData = data[column.realCol] = '';
					}
				} else if (listRow.C == 14) {
					// 列值决定颜色
					if (cellData) {
						var cs = cellData.split('||');
						tr.css({
							background: cs[0]
						});
						if (cs.length > 1) {
							tr.css({
								color: cs[1]
							})
						}
					}
				} else if (listRow.C == 11) {
					// 公式
					return CtlUtils.expression(cellData, listRow.EP || '', a.runtime);
				}
				//return (cellData==undefined? '' : cellData); // Helper.htmlEncode(s);
				if (cellData == undefined || cellData === '')
					return '';
				else {
					if ($.type(cellData) == 'object') {
						// console.log(cellData)
						// return cellData;
						if (cellData.html)
							return $(cellData.html);
						else
							return cellData;
					} else
						return $('<span />').text(cellData).attr('title', cellData);
				}
			},
			visible: function(data) {
				// -99 为表头
				return (data['flag'] != -99);
			},
			editors : function(data, row, col) {
				var column = a.columns[col],
					defCol = column.defCol, 	// profile中定义的cells信息列号
					realCol = column.realCol,	// data中对应的数据列号
					listRow = a.objProp.ListRow[defCol], frm, input;

//					console.log(listRow);
//					console.log(defCol);
//					console.log(a.objProp.ListRow);

				// Modify By Jet
				var editType = listRow.C;
				if (editType == 12){
					// 动态编辑类型
					var mOneCellType = data[listRow.D1-1];
					if (mOneCellType == 0) { 		// 文本输入
						editType = 3;
					} else if (mOneCellType == 1) { // 数值输入
						editType = 4;
					} else if (mOneCellType == 2) { // 日期
						editType = 5;
					} else if (mOneCellType == 3) { // 时间
						editType = 6;
					} else if (mOneCellType == 4) { // 日期加时间
						editType = 7;
					} else if (mOneCellType == 5) { // 下拉
						editType = 12;
					} else {
						editType = 0;
					}
				} else if (editType == 13) {
					// 扩展列编辑
					if (column.editType == 0)
						editType = 3;
					else if (column.editType == 1)
						editType = 4;
					else if (column.editType == 2)
						editType = 5;
					else if (column.editType == 3)
						editType = 6;
					else if (column.editType == 4)
						editType = 7;
					else if (column.editType == 5)
						editType = 121;
					else
						editType = -1;
				}

				if (editType == 121) {
					// 动态扩展列的单元格动态下拉
					var select = $("<select class='dyn_input_inner' />").append('<option value="" />');
					var mChoiceList = {};
					var relSql = column.selectCol;
					if (relSql) {
						relSql = relSql.trim().toLowerCase();
						if (relSql != ''){
							if (a.translater['P' + relSql]){
								mChoiceList = a.translater['P' + relSql];
							}else{
								var mTmpObj = runtime.project.cache[runtime.struct.id + ".PS#"+relSql];
								if (mTmpObj){
									a.translater['P' + relSql] = mTmpObj;
									mChoiceList = mTmpObj;
								}else{
									var mRs=$F.ajaxSync("JSGenerateServlet4",{
														token: runtime.project.token,
														dbPool: "",
	  							 						 name:"Dyn.PublicSql.Get",
	  							 						 pubKey:relSql
													}, runtime.project.digest);
						   			if (mRs.code>0){
										if (mRs.value.count>=0){
											var translationBean={};
											$.each(mRs.value.fields, function(i2, rs){
												translationBean[rs[0]] = rs[1];
											});
											runtime.project.putCache(runtime.struct.id + ".PS#"+relSql, translationBean);
											a.translater['P' + relSql] = translationBean;
											mChoiceList = translationBean;
										}else{
											console.error("动态SQL执行失败:"+column.selectCol+" Err:"+mRs.value.failedDesc);
										}
									}else{
										console.error("动态SQL执行失败:"+column.selectCol+" Err:"+mRs.message);
									}
								}
							}
						} else {
							console.error("动态SQL执行失败,动态SQL为空");
						}
					} else {
						console.error("动态SQL执行失败,动态SQL为空或未指定");
					}
					for(var key in mChoiceList) {
						select.append('<option value="' + key + '">' + mChoiceList[key] + '</option>');
					}
					var oldValue = (data.length > realCol) ? data[realCol] : '';
					select.val(oldValue);
					select.change(function(e){
						//console.log('Update table [' + row + ':' + col + '] to ' + select.val() + ", real cell[" + row + ":" + realCol + "]");
						var cd = {};
						cd[row + ',' + realCol] = select.val();
						if (profile.vV) {
							a.instance.fireValue(profile.vV, runtime, {
								type: 1,
								data: cd
							}, a);
						} else {
							data[realCol] = select.val();
						}
						a.wisTable.refresh(row, col);

						// 设置行记录修改标志
						if(data['flag'] !== 2)
							data['flag'] = 1;

						// 调用命令组
						if (parseInt(listRow.Y)) {
							// 定义了命令组，需要触发
							// 单元格值变动时执行命令组: struct.CtlCmdList[10000+(命令组位于当前列+1)]
							var R = {
								CTRL : a,
								EVENT : {
									GRIDROW: row + 1,
									GRIDCOL: realCol + 1,
									ROWDATA: data,
									OLDVALUE: oldValue
								}
							}
							doCmd(a, 'P' + (10000 + defCol + 1), R);
							if (! R['REFRESH'])
								return;
							else if (R['REFRESH'] == 1) {
								a.wisTable.refresh(row);
							} else if (R['REFRESH'] == 2) {
								a.wisTable.refresh();
							}
						}
					});
					return select;
				} else if (editType == 12){
					// 单元格动态下拉
					var select = $("<select class='dyn_input_inner' />").append('<option value="" />');
					var mChoiceList = {};
					var relSql = data[listRow.D2-1];
					if (relSql) {
						relSql = relSql.trim().toLowerCase();
						if (relSql != ''){
							if (a.translater['P' + relSql]){
								mChoiceList = a.translater['P' + relSql];
							}else{
								var mTmpObj = runtime.project.cache[runtime.struct.id + ".PS#"+relSql];
								if (mTmpObj){
									a.translater['P' + relSql] = mTmpObj;
									mChoiceList = mTmpObj;
								}else{
									var mRs=$F.ajaxSync("JSGenerateServlet4",{
														token: runtime.project.token,
														dbPool: "",
	  							 						 name:"Dyn.PublicSql.Get",
	  							 						 pubKey:relSql
													}, runtime.project.digest);
						   			if (mRs.code>0){
										if (mRs.value.count>=0){
											var translationBean={};
											$.each(mRs.value.fields, function(i2, rs){
												translationBean[rs[0]] = rs[1];
											});
											runtime.project.putCache(runtime.struct.id + ".PS#"+relSql, translationBean);
											a.translater['P' + relSql] = translationBean;
											mChoiceList = translationBean;
										}else{
											console.error("动态SQL执行失败:"+listRow.D2+" Err:"+mRs.value.failedDesc);
										}
									}else{
										console.error("动态SQL执行失败:"+listRow.D2+" Err:"+mRs.message);
									}
								}
							}
						} else {
							console.error("动态SQL执行失败,动态SQL为空");
						}
					} else {
						console.error("动态SQL执行失败,动态SQL为空或未指定");
					}
					for(var key in mChoiceList) {
						select.append('<option value="' + key + '">' + mChoiceList[key] + '</option>');
					}
					select.val(data[realCol]);
					select.change(function(e){
						var oldVal = data[realCol];
						//console.log('Update table [' + row + ':' + col + '] to ' + select.val() + ", real cell[" + row + ":" + realCol + "]");
						var cd = {};
						cd[row + ',' + realCol] = select.val();
						if (profile.vV) {
							a.instance.fireValue(profile.vV, runtime, {
								type: 1,
								data: cd
							}, a);
						} else {
							data[realCol] = select.val();
						}
						a.wisTable.refresh(row, col);

						// 设置行记录修改标志
						if(data['flag'] !== 2)
							data['flag'] = 1;

						// 调用命令组
						if (parseInt(listRow.Y)) {
							// 定义了命令组，需要触发
							// 单元格值变动时执行命令组: struct.CtlCmdList[10000+(命令组位于当前列+1)]
							var R = {
								CTRL : a,
								EVENT : {
									GRIDROW: row + 1,
									GRIDCOL: realCol + 1,
									ROWDATA: data,
									OLDVALUE: oldValue
								}
							}
							doCmd(a, 'P' + (10000 + defCol + 1), R);
							if (! R['REFRESH'])
								return;
							else if (R['REFRESH'] == 1) {
								a.wisTable.refresh(row);
							} else if (R['REFRESH'] == 2) {
								a.wisTable.refresh();
							}
						}
					});
					return select;
				} else if (editType>= 3 && editType <= 7) {
					var oldValue;
					if (data.length > realCol)
						oldValue = data[realCol];
					else {
						if (editType == 4)
							oldValue = 0;
						else
							oldValue = '';
					}

					var input = $('<input type="text" class="dyn_input_inner" />').val(oldValue);
					if (editType == 4) {
						// 单元为数字
						Helper.makeNumberInput(input, true);
					} else if (editType == 5) {
						// 日期选择
						input.datetimepicker({
							fixed: true,
						    format: "Y-m-d",
						    timepicker: false
						});
					} else if (editType == 6) {
						// 时间选择
						input.datetimepicker({
							fixed: true,
						    format: "H:i:s",
						    datepicker: false
						});
					} else if (editType == 7) {
						// 日期时间选择
						input.datetimepicker({
							fixed: true,
						    format: "Y-m-d H:i:s"
						});
					}
					input.change(function(e){
						//console.log('Update table [' + row + ':' + col + '] to ' + input.val() + ", real cell[" + row + ":" + realCol + "]");
						var newValue = input.val();
						if (editType == 4)
							newValue = parseFloat(newValue || '0');
						var cd = {};
						cd[row + ',' + realCol] = newValue;
						if (profile.vV) {
							a.instance.fireValue(profile.vV, runtime, {
								type: 1,
								data: cd
							}, a);
						} else {
							data[realCol] = newValue;
						}
						a.wisTable.refresh(row, col);

						// 设置行记录修改标志
						if(data['flag'] !== 2)
							data['flag'] = 1;

						// 调用命令组
						if (parseInt(listRow.Y)) {
							// 定义了命令组，需要触发
							// 单元格值变动时执行命令组: struct.CtlCmdList[10000+(命令组位于当前列+1)]
							var R = {
									CTRL : a,
									EVENT : {
										GRIDROW: row + 1,
										GRIDCOL: realCol + 1,
										ROWDATA: data,
										OLDVALUE: oldValue
									}
								};
							doCmd(a, 'P' + (10000 + defCol + 1), R);
							if (! R['REFRESH'])
								return;
							else if (R['REFRESH'] == 1) {
								a.wisTable.refresh(row);
							} else if (R['REFRESH'] == 2) {
								a.wisTable.refresh();
							}
						}
					}).keypress(function(e){
						if (e.keyCode == 13)
							input.blur();
					}).blur(function(e){
						if (editType > 4) {
							if (data[realCol] != input.val())
								input.trigger('change');
						}
						input.datetimepicker('destroy')
					})
					return input;
				} else if (editType == 10) {
					// 静态下拉选项
					var cacheKey = listRow.H ? (a.runtime.struct.id + '.' + listRow.H) : '';
					// console.log(cacheKey);
					var cacheData = runtime.project.cache[cacheKey];
					if (! cacheData)
						return;

					var makeChange = function(value) {
						var oldVal = data[realCol];
						//console.log('Update table [' + row + ':' + col + '] to ' + value + ", real cell[" + row + ":" + realCol + "]");
						var cd = {};
						cd[row + ',' + realCol] = value;
						if (profile.vV) {
							a.instance.fireValue(profile.vV, runtime, {
								type: 1,
								data: cd
							}, a);
						} else {
							data[realCol] = value;
						}
						a.wisTable.refresh(row, col);

						// 设置行记录修改标志
						if(data['flag'] !== 2)
							data['flag'] = 1;

						// 调用命令组
						if (parseInt(listRow.Y)) {
							// 定义了命令组，需要触发
							// 单元格值变动时执行命令组: struct.CtlCmdList[10000+(命令组位于当前列+1)]
							var R = {
								CTRL : a,
								EVENT : {
									GRIDROW: row + 1,
									GRIDCOL: realCol + 1,
									ROWDATA: data,
									OLDVALUE: oldValue
								}
							}
							doCmd(a, 'P' + (10000 + defCol + 1), R);
							if (! R['REFRESH'])
								return;
							else if (R['REFRESH'] == 1) {
								a.wisTable.refresh(row);
							} else if (R['REFRESH'] == 2) {
								a.wisTable.refresh();
							}
						}
					}
					if (listRow.MS) {
						// 支持多选
						var input = $('<div style="width:100%"/>').wisCombox({
							multi: true,
							onSelected: function(data) {
								if (! data)
									makeChange('', '');
								else {
									var values = [], labels = [];
									$.each(data, function(i, v) {
										labels.push(v.label);
										values.push(v.value)
									})
									makeChange(values.join(','), labels.join(','))
								}
							}
						}), values = [], cs = [];
						if ($.type(data[realCol]) == 'string')
							values = data[realCol].split(',');
						else
							values.push(data[realCol]);
						for(var key in cacheData) {
							cs.push({
								label: cacheData[key],
								value: key
							})
						}
						input.setData(cs).val(values);
						return input.combox;
						/*
						var input = $('<input type="text" class="dyn_input_inner" readonly="true" tabIndex=1 />').val(data[realCol]);
						input.on('click', function(){
							var cs = [], values = [];
							for(var key in cacheData) {
								cs.push({
									label: cacheData[key],
									value: key
								})
							}
							if ($.type(data[realCol]) == 'string') {
								$.each(data[realCol].split(','), function(i, v) {
									values.push(v)
								})
							} else
								values.push(data[realCol])

							var list = $('<div style="background:white;max-width:300px;max-height:300px;z-index:20003" />').wisList({
								multiSelect: 0,
								checkable: true
							}).setData(cs).select(values);
							Helper.drift(list.list, input, function(){
								cs = [];
								$.each(list.getSelected(), function(i, v) {
									cs.push(v.value)
								})
								makeChange(cs.join(','));
							});
						}).on('keydown', function(e) {
							if (e.keyCode == 46 || e.keyCode == 8) {
								input.val('').trigger('change')
							}
						}).on('change', function(){
							makeChange(input.val());
						})
						return input;
						*/
					} else {
						// 仅单选
						var select = $("<select class='dyn_input_inner' />").append('<option value="" />');
						for(var key in cacheData) {
							select.append('<option value="' + key + '">' + cacheData[key] + '</option>');
						}
						select.val(data[realCol]);
						select.change(function(e){
							makeChange(select.val())
						});
					}
					return select;
				} else if (editType == 8) {
					// 动态下拉选项
					var makeChange = function(value, label) {
						var oldVal = data[realCol];
						//console.log('Update table [' + row + ':' + col + '] to ' + value + ", real cell[" + row + ":" + realCol + "]");
						var cd = {};
						cd[row + ',' + realCol] = label;
						cd[row + ',' + (listRow.E-1)] = value;
						if (profile.vV) {
							a.instance.fireValue(profile.vV, runtime, {
								type: 1,
								data: cd
							}, a);
						} else {
							data[realCol] = label;
							data[listRow.E-1] = value
						}
						a.wisTable.refresh(row, col);

						// 设置行记录修改标志
						if(data['flag'] !== 2)
							data['flag'] = 1;

						// 调用命令组
						if (parseInt(listRow.Y)) {
							// 定义了命令组，需要触发
							// 单元格值变动时执行命令组: struct.CtlCmdList[10000+(命令组位于当前列+1)]
							var R = {
								CTRL : a,
								EVENT : {
									GRIDROW: row + 1,
									GRIDCOL: listRow.E,
									ROWDATA: data,
									OLDVALUE: oldValue
								}
							}
							doCmd(a, 'P' + (10000 + defCol + 1), R);
							if (! R['REFRESH'])
								return;
							else if (R['REFRESH'] == 1) {
								a.wisTable.refresh(row);
							} else if (R['REFRESH'] == 2) {
								a.wisTable.refresh();
							}
						}
					}, input;
					if (listRow.MS) {
						// 支持多选
						input = $('<div style="width:100%"/>').wisCombox({
							multi: true,
							onSelected: function(data) {
								if (! data)
									makeChange('', '');
								else {
									var values = [], labels = [];
									$.each(data, function(i, v) {
										labels.push(v.label);
										values.push(v.value)
									})
									makeChange(values.join(','), labels.join(','))
								}
							}
						})
						/*
						input = $('<input type="text" class="dyn_input_inner" readonly="true" tabIndex=1 />');
						input.data('source', []);
						input.on('click', function(){
							var cs = input.data('source'), values = [];
							if ($.type(data[listRow.E-1]) == 'string') {
								$.each(data[listRow.E-1].split(','), function(i, v) {
									values.push(v)
								})
							} else
								values.push(data[listRow.E-1])
							var list = $('<div style="background:white;z-index:20003" />').wisList({
								multiSelect: 0,
								checkable: true
							}).setData(cs).select(values);
							Helper.drift(list.list, input, function(){
								cs = [], values = [];
								$.each(list.getSelected(), function(i, v) {
									cs.push(v.label);
									values.push(v.value)
								})
								makeChange(values.join(','), cs.join(','));
							});
						}).on('keydown', function(e) {
							if (e.keyCode == 46 || e.keyCode == 8) {
								input.val('').trigger('change')
							}
						}).on('change', function(){
							makeChange(input.val(), '');
						})
						*/
					} else {
						input = $("<select class='dyn_input_inner' />").append('<option value="" />');
						// console.log(data[listRow.E-1]);
						input.change(function(e){
							makeChange(input.val(), $("option:checked", input).text())
						});
					}
					var i = listRow.S.indexOf('||'), sqlId = listRow.S.substring(0, i), jsonStr = listRow.S.substring(i+2), params = JSON.parse(jsonStr);
					for(var key in params) {
						var vn = params[key].toLowerCase();
						if (vn[0] == '@') {
							vn = parseInt(vn.substring(1)) - 1;
							params[key] = data[vn];
						} else {
							params[key] = a.instance.getValue(vn, runtime);
						}
					}
					a.runtime.sqlQueue[sqlId] = {
						structId : a.runtime.struct.id,
						params : params,
						callback : function(sqlData) {
							var paramsStr = $F.display(params);
							if (sqlData.count < 0) {
								$F.err('SQLExec - faild', 'DYN[' + a.runtime.struct.id + '] KEY[' + sqlId + '], 控件[' + a.type + '@' + a.id + '][PARAMS: ' + paramsStr + ']');
								sqlData = $.extend({
									columns: [],
									fields: []
								}, sqlData);
							} else {
								if ($E.debug)
									console.log('SQLExec - success', 'DYN[' + a.runtime.struct.id + '] KEY[' + sqlId + '], 控件[' + a.type + '@' + a.id + '][PARAMS: ' + paramsStr + ']');
							}

							if (listRow.MS) {
								// 多选
								var cs = [];
								$.each(sqldata(sqlData, [listRow.V, listRow.F]), function(i, v){
									cs.push({
										label : v[listRow.F],
										value : v[listRow.V]
									})
								});
								input.setData(cs);
								input.val((data[listRow.E-1] || '').split(','))
							} else {
								// 单选
								$.each(sqldata(sqlData, [listRow.V, listRow.F]), function(i, v){
									input.append('<option value="' + v[listRow.V] + '">' + v[listRow.F] + '</option>');
								});
								input.val(data[listRow.E-1]);
							}
							// console.log('Set current value:' + data[listRow.E-1])
						}
					}
					a.instance.sqlexec(a.runtime);
					return (listRow.MS) ? input.combox : input;
				}
			},
			onDblClick : function(data, row, col, e) {
				// console.log(data);
				$.each(a.dblclickCalls, function() {
					this(e, {
						GRIDROW: row + 1,
						GRIDCOL: col + 1,
						ROWDATA: data
					});
				})
			},
			onSelected : function(data, row, col, e) {
				$.each(a.changeCalls, function() {
					this(e, {
						GRIDROW: row + 1,
						GRIDCOL: col + 1,
						ROWDATA: data
					});
				})
			},
			onUnselected : function() {
				$.each(a.changeCalls, function() {
					this(undefined, {
						GRIDROW: -1,
						ROWDATA: []
					});
				})
			},
			onPersonalize: function(data) {
				// console.log(data);
				if (data.type === 'orders' || data.type === 'hidden') {
					localStorage.setItem(a.runtime.struct.id + '.' + a.id, JSON.stringify(data.value))
				}
			},
			onMove : function(cur, tar, data) {
				var newData = data.swap(cur, tar), cs = {};
				cs[cur] = newData[cur];
				cs[tar] = newData[tar];
				a.instance.fireValue(a.profile.vV, a.runtime, {
					type : 1,
					data : cs
				}, a);
			}
		});
//			a.wisTable.grid.bind('keydown', function(e){
//				if (e.keyCode == 67 && e.ctrlKey) {
//					var data = a.wisTable.getSelectedData();
//					if (data) {
//						H5Utils.clip(data, function(){
//							$F.info(i18n.sys.clipSuccess)
//						})
//					}
//				}
//			})

		// register context menu for editable table
		if ($.contextMenu == undefined) {
			$F.alert("Wisdge table require jquery contextMenu plugin support.");
		} else {
			var cmitem = {};
			if (a.objProp.newRow) {
				cmitem['append'] = {name: $F.lang('ctls.table.addnew'), icon: "add"};
				cmitem['copynew'] = {name: '复制并新增', icon: ""};
	            cmitem["sep"] = "---------";
			}
			if (a.objProp.delRow) {
				cmitem['remove'] = {name: $F.lang('ctls.table.remove'), icon: "delete"};
			}
			cmitem['copy'] = {name: '复制行数据', icon: ""};
			if (a.objProp.newRow || a.objProp.delRow) {
				var appendRow = function(newdata) {
	        		var data = a.wisTable.getData();
	        		newdata = newdata || [];
	        		newdata['flag'] = 2;		// 0: normal, 1: updated, 2:created
	        		// data.push(newdata);
	        		a.wisTable.addData(newdata);
	        		if (profile.vV) {
						a.instance.fireValue(profile.vV, runtime, {
							type: 0,
							data: data
						}, a);
	        		}
					// console.log(data);
				}
				$.contextMenu({
			        selector: ('#' + uniqueId + ' .wistable-bdiv'),
			        callback: function(key, options, target) {
			        	appendRow();
			        },
			        items: {'append' : {name: $F.lang('ctls.table.addnew'), icon: "add"}},
			        appendTo: container
			    });
				$.contextMenu({
			        selector: ('#' + uniqueId + ' tr.wistable_row>td'),
			        onShow: function(e) {
			        	$(e).click();
			        },
			        callback: function(key, options, target) {
			        	if (key == 'append') {
			        		appendRow();
			        	} else if (key == 'remove') {
			        		var row = target.parent().attr('data-row');
			        		var data = a.wisTable.getData(), rowdata = data[row];
			        		a.wisTable.removeData(rowdata);
			        		if (rowdata['flag'] !== 2) {
			        			data.removed = data.removed || [];
			        			data.removed.push(rowdata);
			        		}
			        		if (profile.vV) {
								a.instance.fireValue(profile.vV, runtime, {
									type: 0,
									data: data
								}, a);
			        		}
			        		// console.log(a.wisTable.getData());
			        	} else if (key == 'copy') {
			        		var row = target.parent().attr('data-row');
			        		var data = a.wisTable.getData(), rowdata = data[row];
							if (rowdata) {
								H5Utils.clip(rowdata, function(){
									$F.info($F.lang('sys.clipSuccess'))
								})
							}
			        	} else if (key == 'copynew') {
			        		var row = target.parent().attr('data-row');
			        		var data = a.wisTable.getData(), rowdata = data[row];
							if (rowdata) {
								appendRow($.extend(true, [], rowdata));
							}
			        	}
			        },
			        items: cmitem,
			        appendTo: container
			    });
			}
		}

		if (a.custProp.s_state)
			a.state(a.custProp.s_state);
		makeValueAndState(a, data, rowNum);
		return a;
	};

	var ctlTable2_createRow = function(a) {
		var bean = [];
		$.each(a.objProp.ListRow, function(i, listRow){
			bean[i] = '';
		});
		return bean;
	},
	getExtCol = function(data, extCol) {
		for(var i = 0; i<data.length; i ++) {
			if (data[i] == extCol)
				return i;
		}
		return -1;
	};

	ctlTable2.prototype = {
		state : function(e) {
			if (e == undefined)
				return this._state;
			else {
				this._state = e;
				if (e == 1)
					this.dom.hide();
				else {
					this.dom.show();
					this.disable(e == 2);
				}
			}
		},
		disable: function(e, byParent) {
			if (byParent) {
				this.dom.toggleClass('disabled', e || this.disabled);
				this.parentDisabled = e;
			} else {
				this.dom.toggleClass('disabled', e || this.parentDisabled);
				this.disabled = e;
			}
		},

		val : function(t) {
			var a = this;
			if (t == undefined)
				return a.wisTable.getData();
			else {
				if (a.objProp.a) {
					if (t.length == 0)
						t.push([])
					t[0]['flag'] = -99;
				}

				this.value = t;
				// console.log(t)
				this.wisTable.setData(t);
				this.redraw();
				//console.log(a.columns)
				//console.log(t);
				if (a.custProp.tipped)
					Tipped.create($('span', a.wisTable.bDiv), { position: 'topleft' })
			}
			return this;
		},
		evt : function(e) {
			var a = this;
			if (e == undefined) {
				return {
					type: 0,
					data: a.val()
				}
			} else {
				if (e.type) {
					var array = [], ks, row;
					for(var key in e.data) {
						ks = key.split(',');
						if (ks.length == 1) {
							// 整行更新
							if (ks[0] == '-1') {
								a.wisTable.setData(a.wisTable.getData(), 2);
							} else {
								// a.wisTable.getData()[parseInt(ks[0])] = e.data[key];
								a.wisTable.refreshRow(parseInt(ks[0]))
							}
						} else {
							$.each(a.columns, function(i, column) {
								if (column.realCol == parseInt(ks[1])) {
									a.wisTable.refresh(parseInt(ks[0]), i);
									return false;
								}
							})
						}
					}
				} else {
					// console.log(e);
					a.val(e.data);
				}
			}
		},
		bind : function(e, callback) {
			if (e == 'dblclick')
				this.dblclickCalls.push(callback);
			else if (e == 'change')
				this.changeCalls.push(callback);
		},

		triggerChange : function(e) {
			$.each(this.changeCalls, function() {
				this();
			})
		},

		nextRow : function() {
			this.wisTable.selectNext();
		},

		prevRow : function() {
			this.wisTable.selectPrev();
		},

		jumpRow : function(row) {
			this.wisTable.jumpRow(row - 1);
		},


		/**
		 * 全选某列
		 * @param col
		 * @param state
		 * @returns
		 */
		scopeCheck : function(col, state) {
			var a = this;
			if (a.wisTable) {
				if (col < 0)
					return $F.err('Ctls - Table', '全选操作的列号不能小于1');
				if (a.profile.cells[col].otherObj.t != 1)
					return $F.err('Ctls - Table', '列[' + (col + 1) + ']不是多选项，不可进行全选操作');
				var ckbs = $('.js_ckb_' + col, a.wisTable.table);
				$.each(ckbs, function(i, v){
					var $ckb = $(v);
					if ($ckb[0].checked != state)
						$ckb.trigger('click');
				})
			}
		},

		/**
		 * 上移某行
		 * @param row
		 * @returns {Boolean}
		 */
		rowMoveUp : function(row) {
			if (this.wisTable) {
				if (row === undefined)
					row = this.wisTable.getSelectedIndex();
				else
					row = parseInt(row) - 1;

				if (row < 1)
					return false;

				if (this.wisTable.moveUp(row)) {
					var newData = this.wisTable.getData().swap(row, row-1);
					var cs = {};
					cs[row] = newData[row];
					cs[row - 1] = newData[row - 1];
					this.instance.fireValue(this.profile.vV, this.runtime, {
						type : 1,
						data : cs
					}, this);
					return true;
				} else {
					//console.log('TABLE[' + this.id +  '] move up faild')
					return false;
				}
			} else
				return false;
		},

		/**
		 * 下移某行
		 * @param row
		 * @returns {Boolean}
		 */
		rowMoveDown : function(row) {
			if (this.wisTable) {
				if (row === undefined)
					row = this.wisTable.getSelectedIndex();
				else
					row = parseInt(row) - 1;

				if (row + 1 >= this.wisTable.getData().length)
					return false;

				if (this.wisTable.moveDown(row)) {
					var newData = this.wisTable.getData().swap(row, row + 1);
					var cs = {};
					cs[row] = newData[row];
					cs[row + 1] = newData[row + 1];
					this.instance.fireValue(this.profile.vV, this.runtime, {
						type : 1,
						data : cs
					}, this);
					return true;
				} else {
					//console.log('TABLE[' + this.id +  '] move down faild')
					return false;
				}
			} else
				return false;
		},

		/**
		 * 设置列宽
		 * @param col
		 * @param width
		 */
		cellWidth : function(col, width) {
			this.wisTable.setCellWidth(col - 1 + this.flagCols, width);
		},
		setCellWidth : function(col, width) {
			this.cellWidth(col, width);
		},

		/**
		 * 重新排列表格的列顺序
		 * @param orders
		 */
		cellsOrder : function(orders) {
			this.wisTable.setCellsOrder(orders);
		},

		sort : function(col, direct) {
			this.wisTable.sortColumn(col - 1 + this.flagCols, direct);
		},

		setStyle : function(cssStyle) {
			this.dom.css(cssStyle);
		},

		driftLayer : function(layer) {
			var a = this;
			setTimeout(function(){
				var row = a.wisTable.getSelectedRow();
				if (row.length == 0)
					return $F.err('Ctls - table', '当前没有选中的行'), 0;
				var owner = $('td.cur', row), offset = owner.offset();
				layer.drift(offset.top, offset.left, offset.top + owner.outerHeight(), offset.left + owner.outerWidth());
			}, 10)
		},

		makeColumns : function() {
			var a = this;
			a.columns = [];
			a.translater = {};
			a.staticCol = 0;

			// 绘制表头信息
			// objProp {
			//	delRow: 0/1,		是否允许删除行
			//	newRow: 0/1,		是否允许新增行
			// 	ListRow: [
			// 		{
			//  		N：xxx, 		列标签
			//			W: xx,		列宽
			//			A：x,		对齐方式(0=左对齐，1=居中，2=右对齐)
			//			R: int		值在SQL查询结果中的列号
			//			E: int		值在SQL查询结果中的列号扩展（仅用于不规则选项等特殊应用）
			//			C: int		编辑类型(0:显示，1：checkbox，2：翻译，3：文字，4：数字，5：日期，6：时间，7：日期时间，8:combo动态选项，9：按钮，10：combo静态选项， 12：不规则单元格)
			//			B: string	列颜色（前景，背景）
			//			H: cacheKey	选项型编辑器的选项数据对象缓存主键
			//			S: sqlId	选项型编辑器的选项数据SQL主键
			//			F: string	选项型编辑器的选项显示对应的SQL返回结果字段名（或列号）
			//			V: string	选项型编辑器的选项值对应的SQL返回结果字段名（或列号）
			//			Y: boolean	单元格值变动时执行命令组: struct.CtlCmdList[10000+(命令组位于当前列+1)]
			// 		}]
			//	}
			// 创建一个新的sql执行队列
			var tmpRuntime = {
				struct: a.runtime.struct,
				sqlQueue : {}
			}

			$.each(a.objProp.ListRow, function(col, listRow){
				//console.log(listRow)
				if (listRow.C == 13) {
					// 动态扩展列
					var i = listRow.S.indexOf('||');
					var sqlId = listRow.S.substring(0, i), jsonStr = listRow.S.substring(i+2), params = JSON.parse(jsonStr);
					for(var key in params) {
						var vn = params[key].toLowerCase();
						// 需要支持动态刷新
						params[key] = a.instance.getValue(vn, a.runtime);
					}
					tmpRuntime.sqlQueue[sqlId] = {
						structId : a.runtime.struct.id,
						params : params,
						callback : function(data) {
							var paramsStr = $F.display(params);
							if (data.count < 0) {
								$F.err('SQLExec - faild', 'DYN[' + a.runtime.struct.id + '] KEY[' + sqlId + '], 控件[' + a.type + '@' + a.id + '][PARAMS: ' + paramsStr + ']');
								data = $.extend({
									columns : [],
									fields : []
								}, data);
							} else {
								// if (paramsStr.length > 2)
								if ($E.debug)
									console.log('SQLExec - success', 'DYN[' + a.runtime.struct.id + '] KEY[' + sqlId + '], 控件[' + a.type + '@' + a.id + '][PARAMS: ' + paramsStr + ']');
							}
							$.each(data.fields, function(i, v) {
								var column = {
									display : v[1],
									name : 'th_' + col + '_' + i,
									width : listRow.W / 15,
									align : (listRow.A == 2 ? 'right' : (listRow.A == 1 ? 'center' : 'left')),
									sortable : false,
									editable : true,
									defCol: col,
									crossCol: v[0],
									editType: v[2],
									selectCol: v[3],
									realCol: -1
								}
								a.columns.push(column);
							})
						}
					}
					a.instance.sqlexec(a.runtime);
					return true;
				} else if (listRow.C == 2 || listRow.C == 10) {
					// 需要翻译
					var cacheKey = listRow.H ? (a.runtime.struct.id + '.' + listRow.H) : '';
					if (cacheKey && a.runtime.project.cache[cacheKey])
						a.translater['T' + col] = a.runtime.project.cache[cacheKey];
					else {
						tmpRuntime.sqlQueue[listRow.S] = {
							structId : a.runtime.struct.id,
							params: {},
							callback: function(data) {
								if (data.count < 0) {
									$F.err('SQLExec - failed', 'DYN[' + a.runtime.struct.id + '] KEY[' + listRow.S + '], 控件[' + a.type + '@' + a.id + '][PARAMS: {}]');
									data = $.extend({
										columns: [],
										fields: []
									}, data);
								}
								var translationEntity = {};
								if (listRow.C == 2) {
									$.each(data.fields, function(i, v) {
										translationEntity[v[0]] = v[1];
									})
								} else {
									$.each(sqldata(data, [listRow.V, listRow.F]), function(i, v){
										translationEntity[v[listRow.V]] = v[listRow.F];
									});
								}
								a.translater['T' + col] = translationEntity;
								// put data into cache
								if (cacheKey)
									a.runtime.project.cache[cacheKey] = translationEntity;

								if (listRow.C == 10 && listRow.MS) {
									a.multiEntity = a.multiEntity || []
									a.multiEntity.push(col);
								}
							}
						}
					}
				}

				var cw = parseInt(listRow.W || 0);
				if (cw < 0)
					cw = 0;
				var column = {
					display : listRow.N,
					name : 'th_' + col,
					width : Math.max(cw / 15, 0),
					align : (listRow.A == 2 ? 'right' : (listRow.A == 1 ? 'center' : 'left')),
					resizable: true,
					sortable : false,
					editable : true,
					defCol : col,
					realCol : listRow.R - 1,
					wrapable: a.objProp.autoh
				};
				if (! column.width)
					column.forbidden = true;

				a.staticCol = Math.max(column.realCol, a.staticCol)
				if (listRow.B) {
					// 设置列颜色
					var colors = listRow.B.split(',');
					column.color = '#' + colors[0];
					if (colors.length > 1)
						column.bg = '#' + colors[1];
				}
				a.columns.push(column);

				if (listRow.C == 1) {
					// 列为checkbox，设置列表头为checkbox
					if (listRow.N.startWith('#'))
						column.display = listRow.N.substring(1);
					else {
						column.display = $('<input type="checkbox" data-col="' + column.realCol + '" /><label>' + listRow.N + '</label>').on('click', function(e){
							var ckb = $(e.target), c = ckb.attr('data-col'), v = ckb.prop('checked') ? 1 : 0;
							$.each(a.wisTable.getData(), function(){
								this[c] = v;
							})
							a.wisTable.refresh();
						});
					}
				} else if (listRow.C == 14) {
					// 颜色列
					//console.log('find color cell', column)
					a.rowColorCell = column.realCol;
				}
			});
			a.instance.sqlexec(tmpRuntime);

			// 获取本地个性化存储的数据
			var orders = localStorage.getItem(a.runtime.struct.id + '.' + a.id);
			if (orders) {
				orders = JSON.parse(orders)
				var getColumn = function(unit) {
					var c;
					for(var i=0; i<a.columns.length; i++) {
						c = a.columns[i];
						if (c.name == unit.n) {
							if (! unit.v)
								c.hide = true;
							a.columns.splice(i, 1);
							return c;
						}
					}
					return null;
				}
				var resort = [], one;
				$.each(orders, function(i, v) {
					one = getColumn(v);
					if (one)
						resort.push(one);
				})
				a.columns = resort.concat(a.columns);
			}
		},

		redraw : function() {
			this.makeColumns();
			if (this.wisTable) {
				this.wisTable.options.columns = this.columns;
				// this.wisTable.setData([]);
				this.wisTable.redraw();
			}
		},

		hidden : function(columns) {
			this.wisTable.hidden(columns);
		},

		bindProperty: function(propertyName) {
			// 绑定了变量的控件，值改变时触发消息通知给实例
			var a = this;
			propertyName = propertyName.toLowerCase();
			a.bind('change', function(e){
				a.instance.fireValue(propertyName, a.runtime, a.evt(), a);
			});

			// 绑定值消息，当实例改变时，控件同步更新
			a.val(a.instance.getValue(propertyName, a.runtime));
			a.instance.bindValue(propertyName, a, function(e) {
				a.evt(e);
			});
		},

		destroy: function() {
			if (this.wisTable && $.isFunction(this.wisTable.destroy)) {
				this.wisTable.destroy();
			}
		},
		getItem: function(e) {
			return this.attributes[e];
		},
		setItem: function(e, v) {
			this.attributes[e] = v;
			return this;
		}
	};

	/*
	 * 动态页面组件：Tree
	 */
	var cTree = function(container, profile, runtime) {
		return new ctlTree(container, profile, runtime);
	},

	ctlTree = function(container, profile, runtime) {
		var a = this;
		a.id = profile.cId;
		a.type = "TREE";
		a.disabled = false;
		a.instance = runtime.instance;
		a.container = container;
		a.runtime = runtime;
		a.path = runtime.namespace + '.' + a.id;
		a.profile = profile;
		a.objProp = profile.ot || {};
		a.custProp = profile.o2 || {};
		// 选值是否需要包装成SQL格式
		a.valueStyle = 0;
		a.changeCalls = [];
		a.dblclickCalls = [];
		a.parentDisabled = a.disabled = false;
		a.data = [];
		a.attributes = {};
		// console.log(a);

		var q = ctlStyle(a), style = q.style, outerStyle = q.outerStyle, innerStyle = q.innerStyle, clazz = q.clazz;
		if (a.objProp.nl !== 1)
			clazz.push('dyn_border');
		a.dom = $('<div data-type="' + a.type + '" data-path="' + a.path + '" class="' + clazz.join(' ') + '" style="' + getStyles(style, outerStyle, innerStyle) + ';overflow:auto" />').appendTo(container);

		var menuOpr = {};
		if (a.custProp.newcmd)
			menuOpr.add = true;
		if (a.custProp.editcmd)
			menuOpr.edit = true;
		if (a.custProp.delcmd)
			menuOpr.remove = true;
		if (a.custProp.sortable > 1) {
			menuOpr.indent = true;
			menuOpr.protrude = true;
		}
		a.wisTree = a.dom.wisTree({
			showCheck : (a.objProp.mSel ? true : false),
			expandAll : (a.objProp.exp ? true : false),
			includeFolder : (a.custProp.icfather ? true : false),
			includeHalfState : (a.custProp.icall ? false : true),
			cascadeCheck : (a.custProp.norelation ? false : true),
			menuOpr : menuOpr,
			dragable : (a.custProp.sortable ? true : false),
			cross : (a.custProp.sortable > 1),
			lock : (a.custProp.lock ? true : false),
			tabIndex : (a.objProp.nl ? false : 0),
			completely : (a.custProp.asyncload ? false : true),
			awesome: (a.custProp.awesome ? true : false),
			labels : function(t) {
				return t.name;
			},
			onMenuOprInit : function(node, opr) {
				var level = 1, parent = node.parent;
				while(parent) {
					level ++;
					parent = parent.parent;
				}
				if (level == 1)
					opr.indent = false;
				if ($.isFunction(a.menuOprCalback)) {
					return a.menuOprCalback(node, level, opr);
				} else {
					if (a.custProp.oprcmd) {
						var R = {
							CTL: a,
							EVENT : {
								NODE: node,
								LEVEL: level,
								OPR: opr
							}
						}
						a.instance.doCmd('P' + a.custProp.oprcmd, R, a.runtime, a.id);
						return R.EVENT.OPR;
					} else {
						if (level >= a.custProp.maxlevel && a.custProp.maxlevel > 0) {
							delete opr.add;
							delete opr.protrude;
						}
						return opr;
					}
				}
			},
			onSelected : function(data, li) {
				if (a.objProp.mSel)
					return;

				var label = '';
				if (data == undefined) {
					// 等同于onUnselected事件
					a.value = '';
				} else {
					if (a.objProp.everynode && data.children.length > 0)
						return false;
					var real = (data.data === undefined ? data.id : data.data);
					if (a.profile.vV)
						a.value = a.instance.getValueByPropertyName(a.runtime, a.profile.vV, real);
					else
						a.value = real;
					label = data.name;
					if (a.custProp.lbvar) {
						a.instance.fireValue(a.custProp.lbvar, a.runtime, {
							type: 0,
							data: label
						}, a)
					}
					if (a.custProp.nodevar) {
						var node = $.extend({}, data);
						delete node.parent;
						delete node.children;
						a.instance.fireValue(a.custProp.nodevar, a.runtime, {
							type : 0,
							data : node
						}, a)
					}
				}
				$.each(a.changeCalls, function(){
					this();
				})
			},
			onChecked : function(data) {
				if (a.objProp.mSel) {
					var values = [], labels = [], real;
					for(var i=0; i<data.length; i++) {
						if (a.objProp.everynode && data[i].children.length > 0)
							continue;

						real = (data[i].data === undefined ? data[i].id : data[i].data)
						if (a.valueStyle)
							values.push(",'" + real.replace2("'", "''") + "'");
						else
							values.push(real);
						labels.push(data[i].name)
					}

					a.value = values.join(',');
					if (profile.vV)
						a.instance.fireValue(profile.vV, runtime, a.evt(), a);
					if (a.custProp.lbvar) {
						a.instance.fireValue(a.custProp.lbvar, a.runtime, {
							type: 0,
							data: labels.join(',')
						}, a)
					}
					$.each(a.changeCalls, function() {
						this(null, data);
					})
				}
			},
			onAddnew: function(data, callback) {
				if (a.custProp.newcmd) {
					if ($.isFunction(data)) {
						callback = data;
						data = undefined;
					}
					a.instance.doCmd('P' + a.custProp.newcmd, {PARENT : data, callback: function(child) {
						child.pId = (data == undefined ? '': data.id);
						child.flag = 2;
						// console.info(child);
						callback(child);
					}}, a.runtime, a.id);
				}
			},
			onEdit: function(data, callback) {
				if (a.custProp.editcmd) {
					a.instance.doCmd('P' + a.custProp.editcmd, {DATA : data, callback: function(child) {
						if (child.flag !== 2)
							child.flag = 1;
						callback(child);
					}}, a.runtime, a.id);
				}
			},
			preRemove: function(data, parentData) {
				if (a.custProp.predelcmd) {
					var R = {DATA : data, PARENT : parentData, STOP: 0};
					a.instance.doCmd('P' + a.custProp.predelcmd, R, a.runtime, a.id);
					return (R.STOP ? false : true);
				}
				return true;
			},
			onRemoved: function(data, parentData) {
				if (a.treedata) {
					if (! a.treedata.removed)
						a.treedata.removed = [];
					a.treedata.removed.push(data);
				}
				if (a.custProp.delcmd) {
					a.instance.doCmd('P' + a.custProp.delcmd, {DATA : data, PARENT : parentData}, a.runtime, a.id);
				}
			},
			onMoveIn: function(data, parentData) {
				data.pId = parentData.id;
				//console.log(data.name + ' move in to ' + (parentData.name || '<root>'));
				if (a.custProp.incmd) {
					a.instance.doCmd('P' + a.custProp.incmd, {
						EVENT: {
							CHILD: data,
							PARENT: parentData
						}
					}, a.runtime, a.id);
				}
			},
			onMoveOut: function(data, parentData) {
				//console.log(data.name + ' move out from ' + (parentData.name || '<root>'));
				if (a.custProp.outcmd) {
					a.instance.doCmd('P' + a.custProp.outcmd, {
						EVENT: {
							CHILD: data,
							PARENT: parentData
						}
					}, a.runtime, a.id);
				}
			},
			onIndex: function(children) {
				// console.log('index:' + i, data)
				if (a.custProp.idxcmd) {
					a.instance.doCmd('P' + a.custProp.idxcmd, {
						EVENT: {
							REORDERS: children
						}
					}, a.runtime, a.id);
				}
			}
		});

		// id: 树结构的节点ID字段 - 对应数据库结构字段名
		// desc: 树结构节点描述字段 - 对应数据库结构字段名
		// pId: 树结构的父节点ID字段 - 对应数据库结构字段名
		// value: @FIELDNAME 树结构的节点值字段 - 对应数据库结构字段名
		// everynode: 1=只能选末级节点
		// mSel: 0/1 是否允许多选
		// cacheId: 数据缓存ID
		// sql: 数据库查询SQL KEY
		// 处理动态加载数据选项
		// console.log(a.objProp)
		if (a.objProp.varsource) {
			// 绑定了数据源变量
			a.instance.bindValue(a.objProp.varsource, a, function(e) {
				ctlTree_dataSource(a, e.data);
			})
			ctlTree_dataSource(a, a.instance.getValue(a.objProp.varsource, a.runtime))
		} else {
			var cacheKey = a.objProp.cacheId ? (a.runtime.struct.id + '.' + a.objProp.cacheId) : '';
			if (cacheKey && runtime.project.cache[cacheKey]) {
				a.treedata = runtime.project.cache[cacheKey];
				a.wisTree.setData(a.treedata);
				// 从实例获得默认值
				if (profile.vV)
					a.val(a.instance.getValue(profile.vV, runtime));
			} else {
				// 变量传参遍历
				var params = {};
				if (profile.relvars) {
					$.each(profile.relvars, function(i, v) {
						// console.log(v);
						params[v.Rel] = a.instance.getValue(v.pro, runtime);
						a.instance.bindValue(v.pro, a, function(e) {
							params[v.Rel] = e.data;
							// 创建回调选项方法
							ctlTree_getNodes(a, params);
						});
					});
				}
				// 从实例获得默认值
				ctlTree_getNodes(a, params);
			}
		}

		if (a.custProp.s_state)
			a.state(a.custProp.s_state);
		makeValueAndState(a);
		return a;
	},

	ctlTree_getNodes = function(ctl, params) {
		var a = ctl;
		a.runtime.sqlQueue[a.objProp.sql] = {
			structId : a.runtime.struct.id,
			params : params,
			callback : function(data) {
				// console.log(data);
				var paramsStr = $F.display(params);
				if (data.count < 0) {
					$F.err('SQLExec - failed', 'DYN[' + a.runtime.struct.id + '] KEY[' + a.objProp.sql + '], 控件[' + ctl.type + '@' + ctl.id + '][PARAMS: ' + paramsStr + ']');
				} else {
					if ($E.debug)
						console.log('SQLExec - success', 'DYN[' + a.runtime.struct.id + '] KEY[' + a.objProp.sql + '], 控件[' + ctl.type + '@' + ctl.id + '][PARAMS: ' + paramsStr + ']');
					// 进行树整理
					try {
						var vf = a.objProp.value || a.objProp.id;
						if (vf.startWith("@")) {
							vf = vf.substring(1);
							a.valueStyle = 1;
						}
						//console.log(data)
						a.treedata = $F.collectTree(data, vf, a.objProp.pId, a.objProp.desc);
						if (a.custProp.precmd) {
							a.treeData = $F.treeEach(a.treedata, function(data) {
								a.instance.doCmd('P' + a.custProp.precmd, {
									EVENT: {
										DATA: data
									}
								}, a.runtime, a.id)
							});
						}
						var cacheKey = a.objProp.cacheId ? (a.runtime.struct.id + '.' + a.objProp.cacheId) : '';
						if (cacheKey)
							// 缓存结果
							a.instance.project.cache[cacheKey] = a.treedata;

						a.wisTree.setData(a.treedata);
					}catch(e) {
						console.error(e);
					}

					//console.log(treedata);
					if (a.profile.vV) {
						a.val(a.instance.getValue(a.profile.vV, a.runtime));
					}
				}
			}
		}
	},

	ctlTree_dataSource = function(ctl, data) {
		ctl.treedata = $F.collectTree({fields:data}, ctl.objProp.varvalue || ctl.objProp.varkey, ctl.objProp.varparent, ctl.objProp.vardesc);
		ctl.wisTree.setData(ctl.treedata);
		ctl.data = data;
	};

	ctlTree.prototype = {
		state : function(e) {
			if (e == undefined)
				return this._state;
			else {
				this._state = e;
				if (e == 1)
					this.dom.hide();
				else {
					this.dom.show();
					this.disable(e == 2);
				}
			}
		},
		disable: function(e, byParent) {
			if (byParent) {
				this.dom.toggleClass('disabled', e || this.disabled);
				this.parentDisabled = e;
			} else {
				this.dom.toggleClass('disabled', e || this.parentDisabled);
				this.disabled = e;
			}
		},

		val : function(t) {
			var a = this;
			if (t == undefined) {
				return a.value;
			} else {
				if (t == null)
					t = '';

				if ((a.value || '') == t)
					return;

				a.value = t;
				if (a.objProp.mSel) {
					a.wisTree.clearCheck();
					if ($.type(t) == 'string') {
						// console.log(t);
						var s = t.split(','), node;
						$.each(s, function(i, v){
							if (a.valueStyle)
								v = v.replace2("'", "");
							a.wisTree.check(v);
						})
						a.wisTree.triggerChecked();
					} else {
						$F.err('Ctls - Tree', '树控件绑定的变量必须是字符串类型: ' + $.type(t))
					}
				} else {
					a.wisTree.select(t);
				}

				return a;
			}
		},

		evt : function(e) {
			if (e == undefined)
				return {
					type: 0,
					data: this.val()
				}
			else
				this.val(e.data);
		},

		bind : function(e, callback) {
			if (e == 'dblclick')
				this.dblclickCalls.push(callback);
			else if (e == 'change')
				this.changeCalls.push(callback);
		},

		triggerChange : function(e) {
			$.each(this.changeCalls, function(){
				this();
			})
		},

		filter : function(e, reverse) {
			this.wisTree.filter(e, reverse);
		},

		filterById : function(e, reverse) {
			var a = this;
			if (a.realData)
				a.wisTree.setData(a.realData);
			this.wisTree.filterById(e, reverse);
		},

		/**
		 * 截取某个子节点作为树展示
		 * @param id
		 */
		subNodeById : function(id) {
			var a = this;
			if (! a.realData)
				a.realData = a.wisTree.getData();

			var getNodeById = function(nodes, id) {
				for(var i=0; i<nodes.length; i ++) {
					//console.log(nodes[i]);
					if (nodes[i].id == id)
						return nodes[i];
					if (nodes[i].folder && nodes[i].children) {
						var v = getNodeById(nodes[i].children, id);
						if (v)
							return v;
					}
				}
				return null;
			}
			var target = getNodeById(a.realData.children, id);
			if (target)
				a.wisTree.setData({
					folder: true,
					children: [target]
				});
			else
				a.wisTree.setData([]);
		},

		search : function(e) {
			var a = this, li = a.wisTree.search(e);
			if (li) {
				if (li.offset().top < a.dom.offset().top || li.offset().top > (a.dom.offset().top + a.dom.height()))
					a.dom.scrollTop(li.offset().top - a.dom.offset().top + a.dom.scrollTop());
			}
		},

		setStyle : function(cssStyle) {
			this.dom.css(cssStyle);
		},

		redraw : function(params) {
			this.custProp.delcmd = params.delcmd;
			this.custProp.editcmd = params.editcmd;
			this.custProp.newcmd = params.newcmd;
			this.wisTree.redraw({
				menuOpr: {
					add: params.newcmd,
					edit: params.editcmd,
					remove: params.delcmd,
					indent: params.indent,
					protrude: params.indent
				},
				cross: params.indent
			});
		},

		destroy: function() {
			if (this.wisTree && $.isFunction(this.wisTree.destroy)) {
				this.wisTree.destroy();
			}
		},
		getItem: function(e) {
			return this.attributes[e];
		},
		setItem: function(e, v) {
			this.attributes[e] = v;
			return this;
		}

	};

	var cTimeline = function(container, profile, runtime, data, rowNum) {
		return new ctlTimeline(container, profile, runtime, data, rowNum);
	},

	ctlTimeline = function(container, profile, runtime, data, rowNum) {
		var a = this;
		a.id = profile.cId + (rowNum == undefined? '' : ('-' + rowNum));
		a.type = "TIMELINE";
		a.disabled = false;
		a.instance = runtime.instance;
		a.container = container;
		a.runtime = runtime;
		a.path = runtime.namespace + '.' + a.id;
		a.profile = profile;
		a.objProp = profile.ot || {};
		a.custProp = profile.o2 || {};
		a.xitemRow = rowNum;
		a.parentDisabled = a.disabled = false;
		a.attributes = {};
		//console.log(a);

		var q = ctlStyle(a), style = q.style, outerStyle = q.outerStyle, innerStyle = q.innerStyle, clazz = q.clazz, attrs= '';
		a.dom = $('<div data-type="' + a.type + '" data-path="' + a.path + '" class="' + clazz.join(' ') + '" style="' + getStyles(style, outerStyle) + '" />').appendTo(container);
		a.ul = $('<ul class="timeline"/>').appendTo(a.dom);
		if (a.custProp.direct)
			a.ul.addClass('reverse');
		if (a.custProp.twoside)
			a.ul.addClass('twoside');

		if (a.custProp.s_state)
			a.state(a.custProp.s_state);
		makeValueAndState(a, data, rowNum);
		return a;
	};

	ctlTimeline.prototype = {
		state : function(e) {
			if (e == undefined)
				return this._state;
			else {
				this._state = e;
				if (e == 1)
					this.dom.hide();
				else {
					this.dom.show();
					this.disable(e == 2);
				}
			}
		},
		disable: function(e, byParent) {
			if (byParent) {
				this.dom.toggleClass('disabled', e || this.disabled);
				this.parentDisabled = e;
			} else {
				this.dom.toggleClass('disabled', e || this.parentDisabled);
				this.disabled = e;
			}
		},

		val : function(e) {
			var a = this;
			if (e == undefined) {
				return a.value;
			} else {
				a.ul.empty().html('');
				if ($.type(e) !== 'array') {
					$F.err('不合法的数组对象使用在时间轴上');
					return;
				}
				if (a.custProp.direct)
					e = e.reverse();

				var li, direct, timeline, date, time, title, content, icon;
				$.each(e, function(i, v) {
					timeline = $F.parseDate(v[0]);
					date = timeline.format('yyyy/MM/dd');
					time = timeline.format('HH:mm');
					title = Helper.filterXSS(v[1]);
					content = Helper.filterXSS(v[2]).replace('\n', '<br/>');
					icon = a.icon ? v[3] : 'tree';
					if (i%2 && a.custProp.twoside) {
						li = $('<li>'
						+ '<span class="content"><h2 class="title">' + title + '</h2><p class="js_content">' + content + '</p></span>'
						+ '<span class="icon"><i class="vl ' + $F.fas(icon) + '" /></span></span>'
						+ '<span class="times"><span class="vl"><span class="date">' + date + '</span><span class="time">' + time + '</span></span></span>'
						+ '</li>').data('bean', v).appendTo(a.ul);
					} else {
						li = $('<li>'
						+ '<span class="times"><span class="vl"><span class="date">' + date + '</span><span class="time">' + time + '</span></span></span>'
						+ '<span class="icon"><i class="vl ' + $F.fas(icon) + '" /></span></span>'
						+ '<span class="content"><h2 class="title">' + title + '</h2><p class="js_content">' + content + '</p></span>'
						+ '</li>').data('bean', v).appendTo(a.ul);
					}
					if (a.callback) {
						li.css('cursor', 'pointer');
						$('.js_content',li).on('click', function(e) {
							var this$ = $(e.currentTarget);
							a.callback(e, {
								DATA: this$.data('bean')
							})
						}).data('bean', v)
					}
				})
				return a;
			}
		},
		evt : function(e) {
			if (e == undefined) {
				return {
					type: 0,
					data: this.val()
				}
			} else
				this.val(e.data);
		},

		bind : function(e, callback) {
			if (e == 'click')
				this.callback = callback;
			else
				this.dom.bind(e, callback);
		},
		getItem: function(e) {
			return this.attributes[e];
		},
		setItem: function(e, v) {
			this.attributes[e] = v;
			return this;
		}
	};

	/*
	 * 动态页面组件：Page
	 */
	var cPage = function(container, profile, runtime) {
		return new ctlPage(container, profile, runtime);
	},

	ctlPage = function(container, profile, runtime) {
		var a = this;
		a.id = profile.cId;
		a.type = "PAGE";
		a.disabled = false;
		a.instance = runtime.instance;
		a.container = container;
		a.runtime = runtime;
		a.path = runtime.namespace + '.' + a.id;
		a.profile = profile;
		a.objProp = profile.ot || {};
		a.custProp = profile.o2 || {};
		a.parentDisabled = a.disabled = false;
		a.attributes = {};
		//console.log(a);

		var q = ctlStyle(a), style = q.style, outerStyle = q.outerStyle, innerStyle = q.innerStyle, clazz = q.clazz;
		a.dom = $('<div data-type="' + a.type + '" data-path="' + a.path + '" class="' + clazz.join(' ') + '" style="' + getStyles(style, outerStyle, innerStyle) + ';height:30px" />').appendTo(container);
		//console.log(profile);
		a.wisPage = a.dom.wisPage({
			callback : function(e){
				a.pageIndex = e;
				a.execute();
			}
		});

		if (a.custProp.s_state)
			a.state(a.custProp.s_state);
		makeValueAndState(a);
		return a;
	};

	ctlPage.prototype = {
		state : function(e) {
			if (e == undefined)
				return this._state;
			else {
				this._state = e;
				if (e == 1)
					this.dom.hide();
				else {
					this.dom.show();
					this.disable(e == 2);
				}
			}
		},
		disable: function(e, byParent) {
			if (byParent) {
				this.dom.toggleClass('disabled', e || this.disabled);
				this.parentDisabled = e;
			} else {
				this.dom.toggleClass('disabled', e || this.parentDisabled);
				this.disabled = e;
			}
		},

		val : function(t) {
			var a = this;
			if (t == undefined)
				return a.value;
			else {
				if (a.profile.ot.mdl) {
					// 采用模板SQL
					if (t !== a.value) {
						a.value = t;
						if (a.value > 0) {
							a.pageIndex = 0;
						} else
							return;
					}
					//console.log(sqlTemp);
				} else {
					// 采用拼接SQL
					t = t.trim();
					if (t.toLowerCase().startWith('select')) {
						a.value = t.substring(6);
						a.pageIndex = 0;
					} else
						a.value = t;
				}
				a.execute();
			}
		},

		execute : function() {
			var a = this, busyId = $F.busyShow();
			if (a.profile.ot.mdl) {
				$F.dataService("CacheDoMDL2", {
					data: {
						token : a.instance.project.token,
						dbPool : a.profile.ot.db,
						sqls : [ {
							cacheId : a.runtime.struct.id,
							sqlId : a.profile.ot.mdl,
							para : a.instance.getSQLValues(a.profile.ot.mdl, a.runtime),
							maxRow: a.profile.ot.rs,
							page: a.pageIndex + 1
						} ]
					},
					digest: a.instance.project.digest,
					success: function(data) {
						a.setData(data);
					},
					fail: function() {
						a.navData();
					},
					always : function(){
						$F.busyHide(busyId);
					}
				})
			} else {
				$F.dataService('SystemDo2', {
					data: $F.sqlbean2('System.General.Info', a.instance.project.token, a.profile.ot.db, [a.value], a.profile.ot.rs, a.pageIndex + 1),
					digest: a.isntance.project.digest,
					success: function(data) {
						a.setData(data);
					},
					fail : function() {
						a.navData();
					},
					always : function(){
						$F.busyHide(busyId);
					}
				});
				//$F.err('Ctls - Page', '拼接SQL模式的分页控件已经不再支持')
				console.error('拼接SQL模式的分页控件很快将不再支持，请尽快修改为SQL模板')
			}
		},

		setData : function(data) {
			var a = this;
			$F.log('Ctrl - Page', '刷新分页器, Page=' + a.pageIndex);
			if (data.code < 0)
				$F.err('Ctls - Page', '(' + a.id + ')' + data.message);
			else {
				if (data.value[0].count >= 0) {
					a.navData(data.value[0]);
				} else {
					a.navData();
				}
			}
		},

		navData : function(data) {
			var a = this;
			if (! data) {
				a.wisPage.nav({
					totalCount: 0,
					pageIndex: 0,
					pageCount: 0
				});
				// 无数据时清空对象值，并隐藏控件
				a.instance.fireValue(a.profile.ot['var'], a.runtime, {
					type: 0,
					data: []
				}, a);
				//a.dom.hide();
				return;
			}
			//a.dom.show();
			a.instance.fireValue(a.profile.ot['var'], a.runtime, {
				type: 0,
				data: data.fields
			}, a);
			a.wisPage.nav({
				totalCount: data.count,
				pageIndex: a.pageIndex,
				pageCount: data.pages
			});

			if ((!a.profile.sV || (a.instance.getValue(a.profile.sV, a.runtime) == 0)) && a.custProp.hide)
				a.dom.toggle(data.pages > 1);
		},

		evt : function(e) {
			if (e == undefined)
				return {
					type: 0,
					data: this.val()
				}
			else
				this.val(e.data);
		},
		bind : function(e, callback) {
		},

		setStyle : function(cssStyle) {
			this.dom.css(cssStyle);
		},

		next : function() {
			this.pageIndex += 1;
			ctlPage_execute(this);
		},

		prev : function() {
			this.pageIndex -= 1;
			this.PageIndex = Math.max(ctl.pageIndex, 0);
			ctlPage_execute(this);
		},
		getItem: function(e) {
			return this.attributes[e];
		},
		setItem: function(e, v) {
			this.attributes[e] = v;
			return this;
		}
	};

	/*
	 * 动态页面组件：Script
	 */
	var cScript = function(container, profile, runtime, data, rowNum) {
		return new ctlScript(container, profile, runtime, data, rowNum);
	},

	ctlScript = function(container, profile, runtime, data, rowNum) {
		var a = this;
		a.id = profile.cId + (rowNum == undefined? '' : ('-' + rowNum));
		a.type = "SCRIPT";
		a.disabled = false;
		a.instance = runtime.instance;
		a.container = container;
		a.runtime = runtime;
		a.path = runtime.namespace + '.' + a.id;
		a.profile = profile;
		a.objProp = profile.ot || {};
		a.custProp = profile.o2 || {};
		a.xitemRow = rowNum;
		a.attributes = {};
		//console.log(a);

		var q = ctlStyle(a), style = q.style, outerStyle = q.outerStyle, innerStyle = q.innerStyle, clazz = q.clazz;
		clazz.push('dyn_script')
		// console.log(getStyles(style, outerStyle, innerStyle));
		if (! style['overflow'])
			style['overflow-y'] = 'auto';
		a.script = a.dom = $('<span data-type="' + a.type + '" data-path="' + a.path + '" class="' + clazz.join(' ') + '" style="' + getStyles(style, outerStyle, innerStyle) + '" />').appendTo(container);
		if (!a.custProp.fragment && a.objProp.S) {
			$F.dataService('SystemDo2', {
				data: $F.sqlbean('DynBD.Select.Script', runtime.project.token, [a.objProp.S]),
				digest: runtime.project.digest,
				success: function(data) {
					if (data.code > 0 && data.value[0].count > 0) {
						a.val(data.value[0].fields[0][0])
					}
				}
			})
		}

		if (a.custProp.s_state)
			a.state(a.custProp.s_state);
		makeValueAndState(a, data, rowNum);
		return a;
	};

	ctlScript.prototype = {
		state : function(e) {
			if (e == undefined)
				return this._state;
			else {
				this._state = e;
				if (e == 1)
					this.dom.hide();
				else {
					this.dom.show();
				}
			}
		},
		disable: function(e, byParent) {
		},

		val : function(t) {
			var a = this;
			if (t == undefined)
				return a.script.html();

			if (a.custProp.fragment) {
				if (t) {
					var busyId = $F.busyShow('Fragment loading...');
					Ajax.post({
						url: $E.url + '/fs/fragments/read_',
						data: {
							path: t,
						},
						success: function(data) {
							if (data.code > 0) {
								a.script.html(Helper.filterXSS(data.value));
								if ($.isFunction(window.prettyPrint))
									window.prettyPrint(null, a.dom[0]);
							} else {
								a.script.html('<div class="red">' + data.message + '</div>')
								$F.err('Ctls - Script', data.message);
							}
						},
						always: function() {
							$F.busyHide(busyId)
						}
					})
				} else
					a.script.empty();
			} else {
				// t = t.replace2('\n', '').replace2('\r', '');
				a.content = t;
				a.translation(true);
				if ($.isFunction(prettyPrint))
					prettyPrint(null, a.dom[0]);
			}
			return a;
		},

		translation : function(binding) {
			var a = this;
			var t = a.content;
			var match = /\[(\w+)\.(\w+)+\]/g.exec(t), r, key, property, missing=[];
			while(match) {
				// console.log(match[0]);
				key = match[0].substring(1, match[0].length-1);
				// 从实例中获取属性值，并且对该属性进行监听联动
				property = a.instance.getProperty(key, a.runtime);
				if (! property) {
					t = t.replace2(match[0], '![' + missing.length + ']!');
					missing.push('[' + key + ']');
				} else {
					r = a.instance.getValue(key, a.runtime);
					if (binding) {
						a.instance.bindValue(key, a, function(e) {
							a.translation();
						});
					}
					t = t.replace2(match[0], r || '');
				}
				match = /\[(\w+)\.(\w+)+\]/g.exec(t);
			}
			match = /\{(\w+)\}/g.exec(t);
			while(match) {
				key = match[0].substring(1, match[0].length-1);
				// 从客户资料中获取值
				if (a.instance.project.customer) {
					r = a.instance.project.customer.getProperty(key);
					if (r == undefined) {
						t = t.replace2(match[0], '![' + missing.length + ']!');
						missing.push('{' + key + '}');
					} else {
						t = t.replace2(match[0], r);
					}
				}
				match = /\{(\w+)\}/g.exec(t);
			}

			for(var i=0; i<missing.length; i++) {
				t = t.replace2('![' + i + ']!', missing[i]);
			}
			a.script.html(Helper.filterXSS(t));
		},

		evt : function(e) {
			if (e == undefined)
				return {
					type: 0,
					data: this.val()
				}
			else
				this.val(e.data);
		},

		bind : function(e, callback) {
			this.script.bind(e, callback);
		},

		triggerChange : function(e) {
			this.script.trigger('click');
		},

		setStyle : function(cssStyle) {
			this.dom.css(cssStyle);
		},
		getItem: function(e) {
			return this.attributes[e];
		},
		setItem: function(e, v) {
			this.attributes[e] = v;
			return this;
		}
	};

	/*
	 * 动态页面组件：BSMenu
	 */
	var cBSMenu = function(container, profile, runtime) {
		return new ctlBSMenu(container, profile, runtime);
	},

	ctlBSMenu = function(container, profile, runtime) {
		var a = this;
		a.id = profile.cId;
		a.type = "BSMENU";
		a.disabled = false;
		a.instance = runtime.instance;
		a.container = container;
		a.runtime = runtime;
		a.profile = profile;
		a.objProp = profile.ot || {};
		a.custProp = profile.o2 || {};
		a.attributes = {};
		//console.log(a);

		if (a.objProp.length > 0) {
			var footer = $('footer'), menuBar = $('<div class="cusmenu" />').appendTo(footer);
			$.each(a.objProp, function(i, v){
				//console.log(v);
				var link = $('<a href="#" class="abbr"></a>');
				if (v.i)
					link.append($F.parseIcon(v.i));
				link.append('<span>' + v.d + '</span>');

				if (v.s) {
					try {
						var state = a.instance.getValue(v.s, runtime);
						if (!state)
							link.appendTo(menuBar);
					} catch(e) {
						$F.err('Ctls - BSMenu', e);
					}
				} else
					link.appendTo(menuBar);
				if (parseInt(v.a))
					link.addClass('active');

				a.activing = false;
				link.on('click', function(e){
					e.preventDefault();
					if (a.activing)
						return;

					// draw sub menus
					link.siblings().removeClass('active');
					link.forceClass('active');
					var subDiv = $('<div class="submenu"/>').appendTo(footer);
					subDiv.empty().html('');
					if (v.su) {
						$.each(v.su, function(i, v){
							//console.log(v);
							var sublink = $('<a href="#" class="abbr"></a>');
							if (v.i)
								sublink.append($F.parseIcon(v.i));
							sublink.append('<span>' + v.d + '</span>');

							if (v.s) {
								try {
									var state = a.instance.getValue(v.s, runtime);
									if (!state)
										sublink.appendTo(subDiv);
								} catch(e) {
									$F.err('Ctls - BSMenu', e);
								}
							} else
								sublink.appendTo(subDiv);
							sublink.on('click', function(e) {
								e.preventDefault();
								if (v.c) {
									a.activing = true;
									$F.process(function(){
										a.instance.doCmd('P' + v.c, {
											CTRL: a
										}, runtime, a.id)
										a.activing = false;
									})
								}
							})
						})
						var this$ = $(e.currentTarget);
						subDiv.css({
							left: this$.position().left,
							width: this$.outerWidth()
						})
						Helper.slide(subDiv, {
							onClose : function() {
								subDiv.remove();
							}
						});
					} else {
						if (v.c) {
							a.activing = true;
							$F.process(function(){
								a.instance.doCmd('P' + v.c, {
									CTRL: a
								}, runtime, a.id);
								a.activing = false;
							}, 'Loading...')
						}
					}
				})
			});
			a.instance.extendBSMenu = menuBar;
		}


		var ctlCmds = runtime.struct.CtlCmdList[a.id];
		if (ctlCmds && ctlCmds['P55']) {
			// 执行控件的渲染时命令
			a.instance.dc.doCmdList('P55@' + a.path, ctlCmds['P55'], '', {CTRL: a}, runtime);
		}
		return a;
	};

	ctlBSMenu.prototype = {
		state : function(e) {
		},
		disable : function(e, byParent) {
		},
		val : function(t) {
		},
		evt : function(e) {
		},
		bind : function(e, callback) {
		},
		setStyle : function(cssStyle) {
			this.dom.css(cssStyle);
		},
		getItem: function(e) {
			return this.attributes[e];
		},
		setItem: function(e, v) {
			this.attributes[e] = v;
			return this;
		}
	};

	/*
	 * 动态页面组件：Progress
	 */
	var cProgress = function(container, profile, runtime, data, rowNum) {
		return new ctlProgress(container, profile, runtime, data, rowNum);
	},

	ctlProgress = function(container, profile, runtime, data, rowNum) {
		var a = this;
		a.id = profile.cId + (rowNum == undefined? '' : ('-' + rowNum));
		a.type = "PROGRESS";
		a.disabled = false;
		a.instance = runtime.instance;
		a.container = container;
		a.runtime = runtime;
		a.path = runtime.namespace + '.' + a.id;
		a.profile = profile;
		a.objProp = profile.ot || {};
		a.custProp = profile.o2 || {};
		a.xitemRow = rowNum;
		a.attributes = {};
		//console.log(a);

		var q = ctlStyle(a), style = q.style, outerStyle = q.outerStyle, innerStyle = q.innerStyle, clazz = q.clazz;
		a.dom = $('<span data-type="' + a.type + '" data-path="' + a.path + '" class="' + clazz.join(' ') + '" style="' + getStyles(style, outerStyle, innerStyle) + '" />').appendTo(container);
		if (! a.custProp.spliter) {
			a.dom.progressbar({
				value: false
			});
			if (a.objProp.changeColor) {
				a.instance.bindValue(a.objProp.changeColor, a, function(e) {
					$(".ui-progressbar-value", a.dom).css({
						'background': e.data
						//"background": '#' + Math.floor( Math.random() * 16777215 ).toString( 16 )
					});
				});
			}
		}

		if (a.custProp.s_state)
			a.state(a.custProp.s_state);
		makeValueAndState(a, data, rowNum);
		return a;
	};

	ctlProgress.prototype = {
		state : function(e) {
			if (e == undefined)
				return this._state;
			else {
				this._state = e;
				if (e == 1)
					this.dom.hide();
				else
					this.dom.show();
			}
		},
		disable: function(e, byParent) {
		},

		val : function(t) {
			var a = this;
			if (t == undefined)
				return a.value;
			else {
				a.value = t;
				if (a.custProp.spliter) {
					if (t instanceof Array) {
						// 获取最大值
						var max = 0;
						$.each(t, function(i, v) {
							max += v.value;
						})
						a.makeSplite(max);
						a.dom.off('resize').on('resize', function(){
							a.makeSplite(max);
						});
					} else
						$F.err('Ctls - Progress', '不合法的分段数据')
				} else {
					a.dom.progressbar("option", {
						value : t
					});
				}
				return a;
			}
		},

		makeSplite: function(max) {
			var a = this, bw = a.dom.width(), w;
			a.dom.empty();
			$.each(a.value, function(i, v) {
				w = Math.floor(bw * v.value / max);
				$('<span class="sub">' + (v.value + (a.custProp.unit || '')) + '</span>')
					.data('entry', v)
					.appendTo(a.dom)
					.css({
						'width': w + 'px',
						'height': '100%',
						'background': v.background,
						'color': v.color,
						'float': 'left',
						'textAlign': 'center'
					})
			})
		},

		evt : function(e) {
			return this.val(e.data);
		},

		bind : function(e, callback) {
		},

		setStyle : function(cssStyle) {
			this.dom.css(cssStyle);
		},
		getItem: function(e) {
			return this.attributes[e];
		},
		setItem: function(e, v) {
			this.attributes[e] = v;
			return this;
		}
	};

	/*
	 * 动态页面组件：Audio
	 */
	var cAudio = function(container, profile, runtime, data, rowNum) {
		return new ctlAudio(container, profile, runtime, data, rowNum);
	},

	ctlAudio = function(container, profile, runtime, data, rowNum) {
		var a = this;
		a.id = profile.cId + (rowNum == undefined? '' : ('-' + rowNum));
		a.type = "AUDIO";
		a.disabled = false;
		a.instance = runtime.instance;
		a.container = container;
		a.runtime = runtime;
		a.path = runtime.namespace + '.' + a.id;
		a.profile = profile;
		a.objProp = profile.ot || {};
		a.custProp = profile.o2 || {};
		a.xitemRow = rowNum;
		a.attributes = {};
		//console.log(a);

		var q = ctlStyle(a), style = q.style, outerStyle = q.outerStyle, innerStyle = q.innerStyle, clazz = q.clazz;
		if (! style['position'])
			style['position'] = 'absolute';
		a.dom = $('<audio id="audio2" style="' + getStyles(style, outerStyle, innerStyle) + ';height:40px;" title="" controls="controls" preload="auto" autobuffer="true" autoplay="autoplay"></audio>').appendTo(container);
		a.input = a.audio = a.dom.audio({
			skin : profile.sty || '',
			source : '',
			autoplay : a.custProp.autoplay,
			onPlay: function(src) {
				//console.log('Playing: ', src)
			},
			onRatechange: function(e) {
				//console.log('Rate: ', e);
			},
			onSeeked: function(e) {
				if (a.custProp.seekcmd) {
					a.instance.doCmd('P' + a.custProp.seekcmd, {
						CTRL: a,
						EVENT: e
					}, a.runtime, a.id)
				}
			}
		})
		a.audio.dom.attr('data-type', a.type).attr('data-path', a.path).addClass(clazz.join(' '));
		a.audio.tip.text(a.profile.lD || '');

		if (a.custProp.s_state)
			a.state(a.custProp.s_state);
		makeValueAndState(a, data, rowNum);
		return a;
	};

	ctlAudio.prototype = {
		state : function(e) {
			if (e == undefined)
				return this._state;
			else {
				this._state = e;
				if (e == 1)
					this.dom.hide();
				else {
					this.dom.show();
				}
			}
		},
		disable: function(e, byParent) {
		},
		val : function(t) {
			var a = this;
			if (t == undefined)
				return '';//a.audio.source();
			else {
				if (t == null || t.trim() == '')
					a.audio.source('');
				else {
					if (t.toLowerCase().startWith('http'))
						a.audio.source(t);
					else {
						var url;
						if (t.startWith('vr/'))
							url = $E.url + '/' + t;
						else if (t.startWith('/vr/'))
							url = $E.url + t;
						else if (t.startWith('VRS#')) {
							var t2 = t.substring(4);
							var cs = t2.split('||');
							if (cs.length > 1)
								url = $E.vrsUrl + '/GetRecord?id=' + encodeURI(cs[0]) + '&queryType=' + cs[1];
							else
								url = $E.vrsUrl + '/GetRecord?id=' + encodeURI(t2) + '&queryType=record_guid';
						} else if (t.startWith('FS#')) {
							url = $E.url + '/fs/get?file=' + t.substring(3);
						} else
							url = 'http://localhost:9833/recordfile?' + t;

						if (url) {
							a.audio.source(url);
							// console.log('AudioPlayer', url);
						}
					}
						/*
						var xhr = new XMLHttpRequest();
						xhr.responseType = 'blob';
						xhr.onreadystatechange = function(){
							if (xhr.readyState=== 4 && xhr.status === 200){
								a.audio.player.src = URL.createObjectURL(new Blob([xhr.response],{type:'audio/mp3'}));
								a.audio.play();
							}
						}
						xhr.open("GET", 'medias/test', true);
						xhr.overrideMimeType("text/plain; charset=x-user-defined");
						xhr.send(null);
						*/
				}
			}
		},
		evt : function(e) {
			if (e == undefined) {
				return {
					type: 0,
					data: this.val()
				}
			} else
				this.val(e.data);
		},
		bind : function(e, callback) {
		},
		pause : function() {
			this.audio.pause();
		},
		play : function() {
			this.audio.play();
		},
		rate : function(e) {
			this.audio.rate(e);
		},
		seek : function(e) {
			this.audio.seek(e);
		},
		restart : function() {
			this.audio.restart();
		},
		mute : function(e) {
			this.audio.mute(e);
		},

		setStyle : function(cssStyle) {
			this.dom.css(cssStyle);
		},
		getItem: function(e) {
			return this.attributes[e];
		},
		setItem: function(e, v) {
			this.attributes[e] = v;
			return this;
		}
	};

	/*
	 * 动态页面组件：Video
	 */
	var cVideo = function(container, profile, runtime, data, rowNum) {
		return new ctlVideo(container, profile, runtime, data, rowNum);
	},

	ctlVideo = function(container, profile, runtime,data, rowNum) {
		var a = this;
		a.id = profile.cId + (rowNum == undefined? '' : ('-' + rowNum));
		a.type = "VIDEO";
		a.disabled = false;
		a.instance = runtime.instance;
		a.container = container;
		a.runtime = runtime;
		a.path = runtime.namespace + '.' + a.id;
		a.profile = profile;
		a.objProp = profile.ot || {};
		a.custProp = profile.o2 || {};
		a.xitemRow = rowNum;
		a.attributes = {};
		//console.log(a);

		var q = ctlStyle(a), style = q.style, outerStyle = q.outerStyle, innerStyle = q.innerStyle, clazz = q.clazz;
		a.video = $('<video data-type="' + a.type + '" data-path="' + a.path + '" class="' + clazz.join(' ') + '" style="' + getStyles(style, outerStyle, innerStyle) + ';height:40px;" title="" />').appendTo(container);
		a.video.wisPlayer({
//						poster : 'player/echo-hereweare.jpg',
//						source : 'player/echo-hereweare.mp4',
//						track : 'player/echo-hereweare.srt'
				})
		a.dom = a.video.dom.attr('id', a.id);

		if (a.custProp.s_state)
			a.state(a.custProp.s_state);
		makeValueAndState(a, data, rowNum);
		return a;
	};

	ctlVideo.prototype = {
		state : function(e) {
			if (e == undefined)
				return this._state;
			else {
				this._state = e;
				if (e == 1)
					this.dom.hide();
				else {
					this.dom.show();
				}
			}
		},
		disable: function(e, byParent) {
		},
		val : function(t) {
			var a = this;
			if (e !== undefined)
				if (e == null || e.trim() == '')
					a.video.source('');
				else {
					if (e.toLowerCase().startWith('http'))
						a.video.source(e);
					else {
						var url;
						if (e.toUpperCase().startWith('RES#')) {
							url = $E.url + e.substring(4);
						} else if (t.startWith('FS#')) {
							url = $E.url + '/fs/get?file=' + e.substring(3);
						}
						if (url) {
							a.video.source(url);
							if ($E.debug)
								console.log('VideoPlayer => ', url);
						}
					}
			}
		},
		evt : function(e) {
		},
		bind : function(e, callback) {
		},
		setStyle : function(cssStyle) {
			this.dom.css(cssStyle);
		},
		getItem: function(e) {
			return this.attributes[e];
		},
		setItem: function(e, v) {
			this.attributes[e] = v;
			return this;
		}
	};

	/*
	 * 动态页面组件：Panel
	 */
	var cPanel = function(container, profile, runtime, data, rowNum) {
		return new ctlPanel(container, profile, runtime, data, rowNum);
	},

	ctlPanel = function(container, profile, runtime, data, rowNum) {
		var a = this;
		a.id = profile.cId + (rowNum == undefined? '' : ('-' + rowNum));
		a.type = "PANEL";
		a.disabled = false;
		a.instance = runtime.instance;
		a.container = container;
		a.runtime = runtime;
		a.path = runtime.namespace + '.' + a.id;
		a.profile = profile;
		a.objProp = profile.ot || {};
		a.custProp = profile.o2 || {};
		a.xitemRow = rowNum;
		a.xitemData = data;
		a.attributes = {};
		a.parentDisabled = a.disabled = false;
		a.ctls = [];
		// console.info(a);

		var q = ctlStyle(a), style = q.style, outerStyle = q.outerStyle, innerStyle = q.innerStyle, clazz = q.clazz;
		if (! a.objProp.nl)
			clazz.push('dyn_border');
		if (a.custProp.align)
			style['text-align'] = a.custProp.align;

		if (a.objProp.bp) {
			// 使用背景图片
			style['background-image'] = 'url(' + $E.url + '/fs/get?file=' + a.objProp.bp + ')'
			style['background-size'] = '100%'
		}

		if (a.custProp.mt) {
			// 移动终端顶部区域，仅在手机模式时有效
			clazz.push('custFixed');
			if ($E.device == 'mobile') {
				style['float'] = undefined;
				style['top'] = style['left'] = style['right'] = style['bottom'] = 0;
				style['width'] = undefined;
				style['position'] = 'relative';

				var fixedBox = $('header>div.fixed');
				a.dom = $('<div data-type="' + a.type + '" data-path="' + a.path + '" class="' + clazz.join(' ') + '" style="' + getStyles(style, outerStyle, innerStyle) + '" />').appendTo(fixedBox);
				a.box = a.dom;
				panelLoad(a);
				a.instance.extendFixed = a.dom;
			} else {
				a.dom = $('<div data-type="' + a.type + '" data-path="' + a.path + '" class="' + clazz.join(' ') + '" style="' + getStyles(style, outerStyle, innerStyle) + '" />').appendTo(container);
				a.box = a.dom;
				panelLoad(a);
				a.instance.extendFixed = a.dom;
				$F.err('Ctls - Panel', '非手机单页面模式，顶部栏无效, CID=' + a.id);
				return a;
			}
		} else {
			if (a.objProp.f || a.objProp.msg || a.objProp.sp) {
				if (a.objProp.f) {
					// 浮动窗口
					a.dom = $('<div data-type="' + a.type + '" data-path="' + a.path + '" class="' + clazz.join(' ') + ' float-layout" style="display:none" />').appendTo(container);
					style['left'] = style['top'] = undefined;
					a.box = $('<div class="inner" style="' + getStyles(style, outerStyle, innerStyle) + '" />').appendTo(a.dom);
				} else {
					//对话框 与  侧边栏
					if (! style['font-size'])
						style['font-size'] = '12px';
					a.dom = a.box = $('<div data-type="' + a.type + '" data-path="' + a.path + '" class="' + clazz.join(' ') + '" style="' + getStyles(style, outerStyle, innerStyle) + '; position:relative;display:none;box-sizing:content-box" />').appendTo(container);
				}
			} else {
				if (profile.lD) {
					a.dom = $('<fieldset data-type="' + a.type + '" data-path="' + a.path + '" class="' + clazz.join(' ') + '" style="' + getStyles(style, outerStyle,innerStyle) + '" />').appendTo(container);
					a.lb = $("<legend>" + profile.lD + "</legend>").appendTo(a.dom);
				} else {
					if (a.custProp.link) {
						a.dom = $('<a href="javascript:;" data-type="' + a.type + '" data-path="' + a.path + '" class="' + clazz.join(' ') + ' dyn_link" style="' + getStyles(style, outerStyle, innerStyle) + '" />').appendTo(container);
						a.dom.on('click', function(e) {
							e.preventDefault();
							var ev = {
								EVENT: {}
							};
							if (a.xitemData !== undefined) {
								ev.EVENT.ROWDATA = a.xitemData,
								ev.EVENT.GRIDROW = a.xitemRow
							}
							$F.process(function(){
								a.instance.doCmd('P' + a.custProp.link, ev, a.runtime, a.id);
							})
						})
					}
					else
						a.dom = $('<div data-type="' + a.type + '" data-path="' + a.path + '" class="' + clazz.join(' ') + '" style="' + getStyles(style, outerStyle, innerStyle) + '" />').appendTo(container);
				}
				a.box = a.dom; //$('<div style="position:relative;white-space:nowrap" />').appendTo(a.dom);
			}
			//console.log(a.path);
			if (parseInt(a.dom.css('flex-grow'))) {
				// 用于处理弹性布局
				if (a.dom.parent().css('flex-direction') == 'column')
					a.dom.css('height', 'auto');
				else
					a.dom.css('width', 'auto');
				//if (H5Utils.isChromeLegacy) {
					//console.log('弹性布局特殊处理: ' + H5Utils.isChromeLegacy)
					a.dom.css({
						padding: 0
					})
					a.box = $('<div class="wrapper" />').appendTo(a.dom);
					if (style['display'] == 'flex') {
						a.box.css({
							'display' : 'flex',
							'flexFlow' : a.dom.css('flexFlow')
						})
						a.dom.css({
							'display' : 'block',
							'flexFlow' : ''
						});
					}
					a.box.css({
						'overflow' : a.dom.css('overflow')
					})
					a.dom.css({
						'overflow' : ''
					})
				//}
			}
			if (a.custProp.vm) {
				if (a.custProp.vm == 'middle')
					a.box.addClass('dyn_valign_middle')
				else if (a.custProp.vm == 'top')
					a.box.addClass('dyn_valign_top');
				else if (a.custProp.vm == 'bottom')
					a.box.addClass('dyn_valign_bottom');
				else if (a.custProp.vm == 'sub')
					a.box.addClass('dyn_valign_sub');
				else if (a.custProp.vm == 'super')
					a.box.addClass('dyn_valign_super')
			}
			if (a.custProp.clear) {
				a.box.addClass('clear');
			}

			if (! a.custProp.lazy) {
				panelLoad(a);
			}

			a.custProp.s_state = a.custProp.s_state || 0;
			if (a.objProp.f || a.objProp.msg || a.objProp.sp)
				a.custProp.s_state = 1;
			a.state(a.custProp.s_state);
		}
		a.box.data('_dynControl', a)

		makeValueAndState(a, data, rowNum);
		return a;
	},

	panelLoad = function(a) {
		//var busyId = $F.busyShow();
		a.lazyFinished = true;
		if (a.objProp.o) {
			// 嵌套子页面
			var page = $D.getPage(a.runtime, a.objProp.o);
			if (! page) {
				$F.err('Ctl - Panel', '不存在的子页面: ' + a.objProp.o)
			} else {
				if ($E.debug)
					console.log('嵌套子页面: ' + page.id);
				$D.drawCtls(page.ctls, a.box, a.runtime, a.path, a.xitemData, a.xitemRow);
				a.ctls = a.box.data('controls');
				a.instance.afterDraw(a.runtime, page);
			}
		} else {
			if (a.profile.ctls) {
				$D.drawCtls(a.profile.ctls, a.box, a.runtime, a.path, a.xitemData, a.xitemRow);
				a.ctls = a.box.data('controls');
			}
		}

		//$F.busyHide(busyId);
	};

	ctlPanel.prototype = {
		state : function(e) {
			var a = this;
			if (e == undefined)
				return a._state;

			e = parseInt(e);
			a._state = e;
			if (e == 1) {
				if (a.objProp.msg) {
					// 对话框panel
					var dialog = a.dom.data('exDialog')
					if (dialog) {
						// $F.dialogClose(dialog);
					} else
						a.dom.hide();
				} else if (a.objProp.f) {
					if (a.dom.data(Helper.masker.MASKER))
						Helper.masker.hide(a.dom);
					else
						a.dom.hide();
				} else {
					if (a.objProp.sp) {
						if (a.profile.sV)
							a.instance.setValue(a.profile.sV, a.runtime, {type:0, data:1});
					}
					a.dom.hide();
				}
			} else {
				if (a.custProp.lazy && !a.lazyFinished) {
					// 懒加载模式，且未绘制
					panelLoad(a);
				}

				if (a.objProp.f) {
					// 浮动panel
					if (e > 6) {
						// 用于直接显示浮动层，通常用于drift
						a.dom.css('zIndex', 1);
						a.dom.show();
					} else {
						if (a.dom.is(':hidden')) {
							var maskOptions = {
								clickToHide: (e !== 4 && e !== 6), // 当state==4或6时，关闭"点击即隐藏"功能
								fixed: true,
								onOpen : function() {
									var combox;
									$('select', a.dom).each(function() {
										combox = $(this).data('ctrl');
										if (combox && $.isFunction(combox.reset))
											combox.reset();
										//panel里面可能是放的其他plugin，如果plugin里有select，就会报错，所以这里报错不需要了
//										else {
//											$F.err('Ctls - Panel', '没有发现COMBOX控件实例')
//											console.log(this);
//										}
									})
									$('.dyn_ckeditorInput', a.dom).each(function(){
										$(this).data('ckeditor').redraw();
									})
								},
								onClose : function() {
									a.dom.hide().appendTo(a.container);
									if (a.stateProp)
										a.instance.fireValue(a.stateProp, a.runtime, {type:0, data:1}, a);
								}
							}
							if (!e || e == 4) {
								maskOptions.container = a.instance.runtime.container;
								maskOptions.zIndex = 10001;
								//a.dom.closest('.dyn_container');
								//console.log(maskOptions.container)
							}
							Helper.masker.show(a.dom, maskOptions);
						}
					}
				} else if (a.objProp.msg) {
					// 对话框
					if (a.dom.is(':hidden')) {
						a.dom.css({
							left: 0,
							top: 0,
							display: 'block'
						})

						var initFunc = false, submitFunc = false, cancelFunc = false, closeFunc = false;
						initFunc = function() {
							if (a.objProp.l)
								a.instance.doCmd('P' + a.objProp.l, {
									CTRL: a
								}, a.runtime, a.id);
							a.dom.parent().css({
								padding: 10
							})
						}
						if (a.objProp.ok) {
							submitFunc = function(close) {
								var values = {
										CTRL: a,
										CLOSABLE: 0,
										close: close
									};
								a.instance.doCmd('P' + a.objProp.ok, values, a.runtime, a.id);
								//console.log(values);
								if (values.CLOSABLE)
									close();
							}
						}
						if (a.objProp.cl) {
							cancelFunc = function(close) {
								var values = {
									CTRL: a,
									CLOSABLE: 0,
									close: close
								};
								a.instance.doCmd('P' + a.objProp.cl, values, a.runtime, a.id);
								if (values.CLOSABLE > 0)
									close();
							}
						}
						closeFunc = function() {
							if (a.objProp.c)
								a.instance.doCmd('P' + a.objProp.c, {
									CTRL: a
								}, a.runtime, a.id);
							a.dom.hide().appendTo(a.container);
						}

						a.dom.data('exDialog', $F.createDialog(a.dom, {
							title: a.profile.lD || 'EliteCRM',
							closable: a.objProp.btc?false:true,
							removable: true,
							preOpen: initFunc,
							onOpen: function(){
								var combox;
								$('select', a.dom).each(function(){
									combox = $(this).data('ctrl');
									if (combox && $.isFunction(combox.reset))
										combox.reset();
									else {
										$F.err('Ctls - Panel', '没有发现COMBOX控件实例')
										console.info(this);
									}
								})
								$('.dyn_ckeditorInput', a.dom).each(function(){
										$(this).data('ckeditor').redraw();
								})
								// Fixed by kevin
								// for some reason, we don't want validation with browser for us, such like hidden input dom
								$('>form', this).attr('novalidate', true);
							},
							onSubmit: submitFunc,
							onCancel: cancelFunc,
							onClose: closeFunc
						}));
					}
				} else {
					if (a.objProp.sp) {
						// 侧边栏
						var sidebar;
						if (a.objProp.sp == 1)
							sidebar = a.instance.topSideBar;
						else if (a.objProp.sp == 2)
							sidebar = a.instance.bottomSideBar;
						else if (a.objProp.sp == 3)
							sidebar = a.instance.leftSideBar;
						else
							sidebar = a.instance.rightSideBar;
						if (! sidebar) {
							$F.err('Ctls - panel', '对应侧边栏没有设置，请检查动态页面主结构设置');
							return;
						}
						a.dom.css({
							left: 0,
							top: 0,
							display: 'none'
						})

						var appendDom = function() {
							$('i.loading', sidebar).hide();
							if (a.dom.data('_sidebar_loaded'))
								// 避免重复装载，造成控件事件失效
								a.dom.show();
							else {
								sidebar.append(a.dom.show());
								a.dom.data('_sidebar_loaded', true)
							}
							var combox;
							$('select', a.dom).each(function() {
								combox = $(this).data('ctrl');
								if (combox && $.isFunction(combox.reset))
									combox.reset();
								else {
									$F.err('Ctls - Panel', '没有发现COMBOX控件实例', this)
								}
							})
						}
						if (a.objProp.sp == 1 || a.objProp.sp == 2) {
							sidebar.stop();
							if ($('i.loading', sidebar).length == 0)
								sidebar.append('<i class="loading far fa-cog fa-spin" />');
							else
								$('i.loading', sidebar).show();
							sidebar.show().animate({height: sidebar.data('area')}, appendDom);
							sidebar.parent().one('click', function(e) {
								sidebar.animate({height: 0}, function(){
									sidebar.hide();
									if (a.profile.sV)
										a.instance.fireValue(a.profile.sV, a.runtime, {type:0, data:1}, a);
								});
								//a.state(1)
							});
						} else {
							sidebar.stop();
							if ($('i.loading', sidebar).length == 0)
								sidebar.append('<i class="loading far fa-cog fa-spin" />');
							else
								$('i.loading', sidebar).show();
							sidebar.show().animate({width: sidebar.data('area')}, appendDom);
							sidebar.parent().one('click', function(e) {
								sidebar.animate({width: 0}, function(){
									sidebar.hide();
									if (a.profile.sV)
										a.instance.fireValue(a.profile.sV, a.runtime, {type:0, data:1}, a);
								});
								//a.state(1)
							});
						}
						if (sidebar.data("_spry_click") == undefined) {
							sidebar.click(function(e) {
								e.stopPropagation();// 在区域内的点击事件阻止冒泡到document
							});
							sidebar.data("_spry_click", true);
						}
					} else {
						a.dom.show();
					}
				}

				a.disable(e == 2);
			}
		},
		disable: function(e, byParent) {
			var a = this, fakeState = e;
			if (byParent) {
				fakeState = e || a.disabled;
				a.dom.toggleClass('disabled', e || a.disabled);
				a.parentDisabled = e;
			} else {
				a.dom.toggleClass('disabled', e || a.parentDisabled);
				a.disabled = e;
			}
			// 轮询所有子控件，并设置为相同disabled状态
			if (a.ctls) {
				$.each(a.ctls, function(i, v){
					v.disable(fakeState, true);
				})
			}
		},

		val : function(t) {
			if (t == undefined)
				return;
			return this;
		},
		evt : function(e) {
		},
		bind : function(e, callback) {
		},

		drift : function(top, left, bottom, right) {
			if (this.custProp.lazy && ! this.lazyFinished)
				panelLoad(this);
			H5Utils.drift(top, left, bottom, right, this.dom);
		},

		close : function() {
			var a = this;
			if (a.objProp.msg) {
				// 对话框panel
				var dialog = a.dom.data('exDialog')
				if (dialog) {
					$F.dialogClose(dialog);
				}
			}
		},

		setStyle : function(cssStyle) {
			this.dom.css(cssStyle);
		},

		getContainer : function() {
			return this.box;
		},

		toggle : function() {
			var a = this;
			if (a.profile.sV) {
				var state = a.instance.getValue(a.profile.sV, a.runtime);
				if (state)
					a.instance.fireValue(a.profile.sV, a.runtime, {type:0, data:0});
				else
					a.instance.fireValue(a.profile.sV, a.runtime, {type:0, data:1});
			} else {
				// console.info(a.dom.is(':visible'));
				if (a.dom.is(':visible'))
					a.state(1);
				else
					a.state(0);
				// a.dom.toggle();
			}
		},

		label : function(e) {
			if (e == undefined)
				return (this.label ? this.label.text() : '');
			else {
				this.label && this.label.text(e);
				return this;
			}
		},

		drawer : function(direct) {
			var a = this;
			if (a.profile.sV) {
				var state = a.instance.getValue(a.profile.sV, a.runtime);
				if (state)
					a.instance.fireValue(a.profile.sV, a.runtime, {type:0, data:-1}, a);
				else
					a.instance.fireValue(a.profile.sV, a.runtime, {type:0, data:1}, a);
			}

			// console.info(a.dom.is(':visible'));
			a.dom.animate('stop');
			if (a.dom.is(':visible')) {
				var o = a.dom.height();
				a.dom.animate({
					height: 0
				}, 'fast', function() {
					a.dom.css({
						height: o + 'px'
					})
					a.dom.hide();
				})
			} else {
				a.dom.show();
				var height = a.dom.height();
				a.dom.css('height', 0);
				a.dom.animate({
					height: height + 'px'
				}, 'fast')
			}
		},

		data: function() {
			if (arguments.length == 0)
				$F.err('Ctls - Panel', 'Invalide arguments of data function');

			if (arguments.length < 2)
				return this.attributes[arguments[0]];

			this.attributes(arguments[0], arguments[1])
		},

		verify: function() {
			var a = this, ctl;
			var isHidden = function(ctl) {
				if (ctl.state() == 1)
					return true;
				var parentCtl = ctl.container.data('_dynControl');
				if (parentCtl)
					return isHidden(parentCtl);
				return false;
			}
			if (isHidden(a))
				return true;

			for(var i = 0; i<a.ctls.length; i++) {
				ctl = a.ctls[i];
				if ((ctl.type == 'TEXT' || ctl.type == 'NUMBER' || ctl.type == 'DATETIME' || ctl.type == 'COMBOX') && ctl.custProp.required && ctl.val() === '') {
					if (ctl.state() == 1)
						continue;
					$F.alert(ctl.custProp.required + '为必填项目');
					ctl.focus();
					return false;
				} else if (ctl.type == 'PANEL') {
					if (ctl.state() == 1)
						continue;
					var sub = ctl.verify();
					if (! sub)
						return false;
				}
				if (ctl.type == 'TEXT' && ctl.objProp.type < 4 && ctl.custProp.pattern) {
					try {
						var pattern = eval(ctl.custProp.pattern);
						if (! pattern.test(ctl.val())) {
							if (ctl.custProp.regextip)
								$F.alert(ctl.custProp.regextip);
							else
								$F.alert('正则验证未通过：' + ctl.custProp.pattern);
							return false;
						}
					} catch(e) {
						console.error(e);
					}
				}
			}
			return true;
		},
		getItem: function(e) {
			return this.attributes[e];
		},
		setItem: function(e, v) {
			this.attributes[e] = v;
			return this;
		}
	};


	/*
	 * 动态页面组件：Splitter
	 */
	var cSplitter = function(container, profile, runtime, data, rowNum) {
		return new ctlSplitter(container, profile, runtime, data, rowNum);
	},

	ctlSplitter = function(container, profile, runtime, data, rowNum) {
		var a = this;
		a.id = profile.cId + (rowNum == undefined? '' : ('-' + rowNum));
		a.type = "SPLITTER";
		a.disabled = false;
		a.instance = runtime.instance;
		a.container = container;
		a.runtime = runtime;
		a.path = runtime.namespace + '.' + a.id;
		a.profile = profile;
		a.objProp = profile.ot || {};
		a.custProp = profile.o2 || {};
		a.xitemRow = rowNum;
		a.xitemData = data;
		a.parentDisabled = a.disabled = false;
		a.ctls = [];
		a.attributes = {};
		// console.info(a);

		var q = ctlStyle(a), style = q.style, outerStyle = q.outerStyle, innerStyle = q.innerStyle, clazz = q.clazz;
		if (! a.objProp.nl)
			clazz.push('dyn_border');

		if (a.objProp.bp) {
			// 使用背景图片
			style['background-image'] = 'url(' + $E.url + '/fs/get?file=' + a.objProp.bp + ')'
			style['background-size'] = '100%'
		}
		a.dom = $('<div data-type="' + a.type + '" data-path="' + a.path + '" class="' + clazz.join(' ') + '" style="' + getStyles(style, outerStyle, innerStyle) + '" />').appendTo(container);
		a.box = a.dom; //$('<div class="wrapper" />').appendTo(a.dom);

		if (a.profile.ctls) {
			if (a.xitemRow == undefined || a.xitemData.length > 0) {
				if (a.profile.ctls.length != 2) {
					$F.err('Ctls - Splitter', '分割窗的子控件必须是2个面板');
					a.box.hide();
					return;
				}
				var vs = a.profile.ctls;
				for(var i=0; i<2; i++) {
					if (vs[i].cType !== 14 && vs[i].cType !== 215 && vs[i].cType !== 214) {
						$F.err('Ctls - Splitter', '分割窗的子控件必须是面板控件');
						a.box.hide();
						return;
					} else {
						vs[i].cs[0] = vs[i].cs[1] = 0;
						if (! vs[i].o2)
							vs[i].o2 = {};
						vs[i].o2.s_position = 'relative';
						vs[i].o2.s_float = undefined;
						vs[i].o2.s_width = '100%';
						vs[i].o2.s_height = '100%';
					}
				}

				var divA = $('<div class="wrapper" style="overflow:auto" />').appendTo(a.box),
					divB = $('<div class="wrapper" style="overflow:auto" />').appendTo(a.box);

				var options = {
					direct : (a.custProp.direct ? 'v' : 'h'),
					cookie : 'wissplitter.' + runtime.struct.id + '.' + a.id,
					handleGrab : true,
					dockableA : (a.custProp.dockA ? true: false),
					dockableB : (a.custProp.dockB ? true: false),
					resized : function(e) {
						// console.log(e);
					}
				}, minA = parseInt(a.custProp.amin), maxA = parseInt(a.custProp.amax), minB = parseInt(a.custProp.bmin), maxB = parseInt(a.custProp.bmax);
				if (! isNaN(minA))
					options.minA = minA;
				if (! isNaN(maxA))
					options.maxA = maxA;
				if (! isNaN(minB))
					options.minB = minB;
				if (! isNaN(maxB))
					options.maxB = maxB;

				if (a.custProp.adef)
					options.defA = a.custProp.adef;
				if (a.custProp.bdef)
					options.defB = a.custProp.bdef;

				//console.log(options);
				//console.log(a.custProp);

				a.box.wisSplitter(options);
				$D.drawCtls([a.profile.ctls[0]], divA, a.runtime, a.path, a.xitemData, a.xitemRow);
				a.ctls = divA.data('controls');
				$D.drawCtls([a.profile.ctls[1]], divB, a.runtime, a.path, a.xitemData, a.xitemRow);
				a.ctls = a.ctls.concat(divB.data('controls'));
			}
		}

		a.state(a.custProp.s_state || 0);
		makeValueAndState(a, data, rowNum);
	};

	ctlSplitter.prototype = {
		state : function(e) {
			if (e == undefined)
				return this._state;
			else {
				this._state = e;
				if (e == 1) {
					this.dom.hide();
				} else {
					this.dom.show();
					this.disable(e == 2);
				}
			}
		},
		disable: function(e, byParent) {
			var a = this, fakeState = e;
			if (byParent) {
				fakeState = e || a.disabled;
				a.dom.toggleClass('disabled', e || a.disabled);
				a.parentDisabled = e;
			} else {
				a.dom.toggleClass('disabled', e || a.parentDisabled);
				a.disabled = e;
			}
			// 轮询所有子控件，并设置为相同disabled状态
			$.each(a.ctls, function(i, v){
				v.disable(fakeState, true);
			})
		},

		val : function(t) {
			if (t == undefined)
				return;
			return this;
		},
		evt : function(e) {
		},
		bind : function(e, callback) {
		},

		drift : function(top, left, bottom, right) {
			H5Utils.drift(top, left, bottom, right, this.dom);
		},

		setStyle : function(cssStyle) {
			this.dom.css(cssStyle);
		},

		toggle : function() {
			var a = this;
			if (a.profile.sV) {
				var state = a.instance.getValue(a.profile.sV, a.runtime);
				if (state)
					a.instance.fireValue(a.profile.sV, a.runtime, {type:0, data:0});
				else
					a.instance.fireValue(a.profile.sV, a.runtime, {type:0, data:1});
			} else {
				// console.info(a.dom.is(':visible'));
				if (a.dom.is(':visible'))
					a.state(1);
				else
					a.state(0);
				// a.dom.toggle();
			}
		},
		getItem: function(e) {
			return this.attributes[e];
		},
		setItem: function(e, v) {
			this.attributes[e] = v;
			return this;
		}
	};

	/*
	 * 动态页面组件：iFrame
	 */
	var cIFrame = function(container, profile, runtime) {
		return new ctlIFrame(container, profile, runtime);
	},

	ctlIFrame = function(container, profile, runtime) {
		var a = this;
		a.id = profile.cId;
		a.type = "IFRAME";
		a.disabled = false;
		a.instance = runtime.instance;
		a.container = container;
		a.runtime = runtime;
		a.path = runtime.namespace + '.' + a.id;
		a.profile = profile;
		a.objProp = profile.ot || {};
		a.custProp = profile.o2 || {};
		a.attributes = {};
		//console.log(a);

		var q = ctlStyle(a), style = q.style, outerStyle = q.outerStyle, innerStyle = q.innerStyle, clazz = q.clazz;
		if (style['display'] == undefined)
			style['display'] = 'block';
		if (style['width'] == undefined || style['width'] == 'auto')
			style['width'] = '100%';
		a.dom = $('<iframe data-type="' + a.type + '" data-path="' + a.path + '" class="' + clazz.join(' ') + '" style="' + getStyles(style, outerStyle, innerStyle) + '" />').appendTo(container);

		if (a.custProp.s_state)
			a.state(a.custProp.s_state);
		makeValueAndState(a);

		return this;
	};

	ctlIFrame.prototype = {
		state : function(e) {
			if (e == undefined)
				return this._state;
			else {
				this._state = e;
				if (e == 1)
					this.dom.hide();
				else
					this.dom.show();
			}
		},
		disable: function(e) {
		},
		val : function(t) {
			if (t == undefined)
				return this.value;
			else {
				if (! t.toLowerCase().startWith('http'))
					t = 'http://' + t;
				this.value = t;
				this.dom.attr('src', t);
				return this;
			}
		},
		evt : function(e) {
			return this.val(e.data);
		},
		bind : function(e, callback) {
		},

		setStyle : function(cssStyle) {
			this.dom.css(cssStyle);
		},
		getItem: function(e) {
			return this.attributes[e];
		},
		setItem: function(e, v) {
			this.attributes[e] = v;
			return this;
		}
	};

	/*
	 * 动态页面组件：cXItem
	 */
	var cXItem = function(container, profile, runtime, data, rowNum) {
		return new ctlXItem(container, profile, runtime, data, rowNum);
	},

	ctlXItem = function(container, profile, runtime, data, rowNum) {
		var a = this;
		a.id = profile.cId + (rowNum == undefined? '' : ('-' + rowNum));
		a.type = "XITEM";
		a.disabled = false;
		a.instance = runtime.instance;
		a.container = container;
		a.runtime = runtime;
		a.path = runtime.namespace + '.' + a.id;
		a.profile = profile;
		a.objProp = profile.ot || {};
		a.custProp = profile.o2 || {};
		a.xitemRow = rowNum;
		a.xitemData = data;
		a.parentDisabled = a.disabled = false;
		a.attributes = {};
		// console.log(a);

		var q = ctlStyle(a), style = q.style, outerStyle = q.outerStyle, innerStyle = q.innerStyle, clazz = q.clazz;
		if (! a.objProp.nl)
			clazz.push('dyn_border');

		a.dom = $('<div data-type="' + a.type + '" data-path="' + a.path + '" class="dyn_itemlist ' + clazz.join(' ') + '" style="' + getStyles(style, outerStyle, innerStyle) + '" />').appendTo(container);
		a.box = a.ul = $('<ul class="xitem" />').appendTo(a.dom);

		if (a.custProp.s_state)
			a.state(a.custProp.s_state);
		makeValueAndState(a, data, rowNum);

		return a;
	};

	ctlXItem.prototype = {
		state : function(e) {
			if (e == undefined)
				return this._state;
			else {
				this._state = e;
				if (e == 1)
					this.dom.hide();
				else {
					this.dom.show();
				}
			}
		},

		val : function(t) {
			var a = this, start = new Date();
			if (t == undefined) {
				return a.data || [];
			} else {
				if (a.custProp.stepload) {
					var cs = a.custProp.stepload.split('||');
					var sqlId = a.instance.ognl(cs[0], a.runtime)
					a.execute(sqlId, parseInt(cs[1]));
				} else {
					a.data = t;
					a.ul.empty();
					if ($.type(a.data) !== 'array'){
						$F.err('Ctls - xitem', '不合法的数组对象: ', t);
						return this;
					}

					if (a.drawThread) {
						$F.busyHide(a.drawBusyId);
						clearTimeout(a.drawThread);
						a.drawThread = null;
					}
					if (a.profile.ctls && a.profile.ctls.length > 0) {
						if (a.custProp.thread) {
							var lc = function(i) {
								a.drawThread = setTimeout(function(){
									a.appendRow(i, a.data[i]);
									i ++;
									if (i < a.data.length)
										lc(i);
									else {
										a.makeLineNo();
										$F.busyHide(a.drawBusyId);
										a.drawThread = null
									}
								}, 1)
							};
							if (a.data.length > 0) {
								a.drawBusyId = $F.busyShow('绘制数据项中...');
								lc(0);
							}
						} else {
							$.each(a.data, function(i, v){
								a.appendRow(i, v);
							})
							a.makeLineNo();
						}
					}
					if ($E.debug)
						console.log('XITEM绘制完成：' + a.id + ', 耗时' + (new Date() - start) + '\'ms');
				}
				return this;
			}
		},

		evt : function(e) {
			var a = this;
			if (e == undefined)
				return {
					type : 0,
					data : a.val()
				}
			else {
				if (e.type) {
					var ks, r, c;
					for(var key in e.data) {
						ks = key.split(',');
						if (ks[0] == '-1') {
							a.val(a.data);
							return a;
						} else {
							r = parseInt(ks[0]);
							a.drawRow(r, a.ul.find('>li:eq(' + r + ')'), a.data[r]);
						}
					}
					return a;
				} else {
					a.val(e.data);
					return a;
				}
			}
		},

		execute: function(sql, pageSize) {
			var a = this;
			a.step = {
				pageIndex: 1,
				pageSize: pageSize
			};
			if (sql.toLowerCase().startWith('select')) {
				// console.info(sql);
				a.step.type = 0;
				a.step.sql = sql.substring(6);
			} else {
				a.step.type = 1;
				a.step.sql = sql;
			}

			a.stepLoad();
		},

		stepLoad: function() {
			var a = this, busyId = $F.busyShow();
			if (a.step.type == 0) {
				// 采用拼接SQL
				$F.dataService('SystemDo2', {
					data: $F.sqlbean('System.General.Info', a.instance.project.token, [a.step.sql], a.step.pageSize, a.step.pageIndex),
					digest: a.instance.project.digest,
					success: function(data) {
						if (data.code < 0)
							return $F.err('Ctls - xitem', '(' + a.id + ')' + data.message);
						if (data.value[0].count > 0) {
							a.stepDraw(data.value[0]);
						}
					},
					always: function() {
						$F.busyHide(busyId);
					}
				});
			} else {
				// 采用模板SQL
				$F.dataService("CacheDoMDL2", {
					data: {
						token : a.instance.project.token,
						dbPool : '',
						sqls : [ {
							cacheId : a.runtime.struct.id,
							sqlId : a.step.sql,
							para : a.instance.getSQLValues(a.step.sql, a.runtime),
							maxRow: a.step.pageSize,
							page: a.step.pageIndex
						} ]
					},
					digest: a.instance.project.digest,
					success: function(data) {
						if (data.code < 0)
							return $F.err('Ctls - xitem', '(' + a.id + ')' + data.message);
						if (data.value[0].count >= 0) {
							a.stepDraw(data.value[0]);
						}
					},
					always: function() {
						$F.busyHide(busyId);
					}
				})
			}
		},

		stepDraw: function(data) {
			var a = this;
			if (! a.stepData)
				a.stepData = [];
			var pos = a.stepData.length;
			a.stepData = a.stepData.concat(data.fields);
			// console.info(a.stepData);
			if (a.stepStatus)
				a.stepStatus.remove();
			for(var i=pos; i<a.stepData.length; i++) {
				a.appendRow(i, a.stepData[i]);
			}

			console.info(a.step.pageIndex + ' / ' + data.pages);
			if (a.stepStatus)
				a.stepStatus.remove();

			//a.instance.project.makeIScroll();
			if (data.pages > a.step.pageIndex) {
				a.stepStatus = $('<li class="status"></li>').appendTo(a.ul);
				$('<a href="javascript:;" style="font-size:16px;padding:15px;display:block;text-align:right"><i class="far fa-angle-double-right"></i><span> 加载更多...</span></a>')
					.appendTo(a.stepStatus)
					.on('click', function(e){
						e.preventDefault();
						a.step.pageIndex ++;
						a.stepLoad();
					})
//					$('img', a.stepStatus).bind('load', function(){
//						console.info('i am come again.')
//					})
			}
		},

		makeLineNo: function() {
			var a = this, vi = 1;
			$('.xitem_line', a.dom).each(function(i, line) {
				line = $(line);
				if (line.is(':visible')) {
					$('.lineNo', line).text(vi);
					vi++;
				} else {
					$('.lineNo', line).text('');
				}
			})
		},

		appendRow : function(row, data) {
			var a = this, style = '';

			if (a.objProp.lh) {
				// 行距
				style = 'padding-bottom:' + a.objProp.lh + 'px';
				if (a.custProp.nowrap)
					style += ';padding-right:' + a.objProp.lh + 'px';
			}

			if (a.objProp.lc && row > 0) {
				// 分割线
				style += (';border-top:' + a.objProp.lc);
			}
			if (style !== '')
				style = ' style="' + style + '"';

			var li = $('<li class="xitem_line dyn_relative"' + style + '/>').data('entity', data);
			a.drawRow(row, li, data);
			return li.appendTo(a.ul);
		},

		drawRow : function(row, li, data) {
			var a = this, xcmd = a.custProp.xcmd, ucmd = a.custProp.ucmd, clcmd = a.custProp.clcmd;

			// console.log(data)
			li.empty();
			if (data == undefined || data.flag == -99)
				li.hide();
			if (a.custProp.nowrap) {
				li.css('display', 'inline-block');
				if (a.custProp.column > 1) {
					a.ul.css({
						lineHeight: 0
					})
					li.css('width', 100 / a.custProp.column + '%')
				}
			}
			var lineBody = li;
			if (a.custProp.lineno) {
				// 独立行号
				var div = $('<div style="display:block" />').appendTo(li);
				var lineNo = $('<span class="lineNo">' + (row + 1) + '</span>').appendTo(div);
				lineBody = $('<div class="lineBody" />').appendTo(div);
			}
			if (data !== undefined || ! a.custProp.hideempty) {
				// 隐藏空行
				$D.drawCtls(a.profile.ctls, lineBody, a.runtime, a.path, data || [], row);
				a.instance.sqlexec(a.runtime);
			}

			// console.log(v);
			var siblings = {}, binders = {};
			var generateBinders = function(ctls) {
				if (! ctls)
					return;
				$.each(ctls, function(k, ctl) {
					siblings[ctl.profile.cId] = ctl;
					if (ctl.xitemListener) {
						// 控件可以通过binder属性绑定XITEM中的其他列值
						// console.log(ctl.xitemListener)
						for(var col in ctl.xitemListener) {
							if (! binders['c' + col])
								binders['c' + col] = [];
							binders['c' + col].push(ctl.xitemListener[col]);
						}
					}
					ctl.siblings = siblings;
					ctl.xitemBinders = binders;
					if (ctl.profile.rl) {
						// 控件编辑后反写数据对象
						if (ctl.type !== 'TABLE' && ctl.type !== 'TABLE2') {
							ctl.bind('change', function(e) {
								data[ctl.profile.rl-1] = ctl.val();
								if (data['flag'] !== 2)
									data['flag'] = 1;	// 0: normal, 1: updated, 2:created
								if (binders['c' + ctl.profile.rl]) {
									$.each(binders['c' + ctl.profile.rl], function(i, callback) {
										callback(data[ctl.profile.rl-1])
									})
								}
								a.instance.sqlexec(a.runtime);

								//console.log('[' + a.profile.vV + '][' + (row + 1) + '-' + ctl.profile.rl + ']被修改:', ctl.val());
								if (a.profile.vV) {
									var cd = {};
									cd[ctl.xitemRow + ',' + (ctl.profile.rl - 1)] = ctl.val()
									a.instance.fireValue(a.profile.vV, a.runtime, {
										type: 1,
										data: cd
									}, a);
								}
								if (ucmd) {
									a.instance.doCmd('P' + ucmd, {
										EVENT: {
											CTRL: a,
											LINE: li,
											X: row,
											GRIDROW: row + 1,
											ROWDATA: data
										}
									}, a.runtime, a.id);
								}
							})
						} else {
							if (ucmd) {
								ctl.bind('change', function(){
									a.instance.doCmd('P' + ucmd, {
										EVENT: {
											CTRL: a,
											LINE: li,
											X: row,
											GRIDROW: row + 1,
											ROWDATA: data
										}
									}, a.runtime, a.id);
								})
							}
						}
					}
					generateBinders(ctl.ctls);
				})
			}
			generateBinders(lineBody.data('controls'));
			li.data('ctls', siblings);

			if (xcmd) {
				a.instance.doCmd('P' + xcmd, {
					EVENT: {
						CTRL: a,
						LINE: li,
						X: row,
						GRIDROW: row + 1,
						ROWDATA: data
					}
				}, a.runtime, a.id);
			}
			li.on('click', function(e) {
				var classes = 'selected';
				if (a.custProp.highlight)
					classes += ' ' + a.custProp.highlight;
				$('>li', a.ul).removeClass(classes);
				li.forceClass(classes);
				if (clcmd) {
					// XITEM行选择命令已定义
					setTimeout(function() {
						a.instance.doCmd('P' + clcmd, {
							EVENT: {
								CTRL: a,
								GRIDROW: row + 1,
								ROWDATA: data
							}
						}, a.runtime, a.id);
					}, 0)
				}
			})
		},

		remove : function(row) {
			var a = this;
			row = parseInt(row);
			if (isNaN(row) || row < 1)
				return;

			// fixed by kevin, redraw xitem after remvoe
			// 07/02/2018
//			var li = $('>li:eq(' + (row - 1) + ')', a.ul);
//			li.off('click').remove();
//			a.makeLineNo();

			var data = a.data[row - 1];
			a.data.splice(row-1, 1);
			if (data !== undefined && data.flag !== 2) {
				if (! a.data.removed)
					a.data.removed = [];
				a.data.removed.push(data);
			}
			if (a.profile.vV)
				a.instance.fireValue(a.profile.vV, a.runtime, a.evt());
		},

		append : function(data) {
			var a = this;
			if (!a.data)
				a.data = [];
			if (! data)
				data = [];
			data.flag = 2; // 0: normal, 1: updated, 2:created
			a.data.push(data);
			a.appendRow(a.data.length, data);
			a.makeLineNo();

			if (a.profile.vV)
				a.instance.fireValue(a.profile.vV, a.runtime, a.evt(), a);

			return a.data.length;
		},

		insert : function(rowNum) {
			var a = this;
			if (!a.data)
				a.data = [];
			var data = [];
			data.flag = 2; // -1: removed, 0: normal, 1: updated, 2:created, 3: remove after created
			a.data.splice(rowNum, 0, data);

			if (a.profile.vV)
				a.instance.fireValue(a.profile.vV, a.runtime, a.evt());

			return a;
		},

		disable : function(e, byParent) {
			var a = this, fakeState = e;
			if (byParent) {
				fakeState = e || a.disabled;
				a.dom.toggleClass('disabled', e || a.disabled);
				a.parentDisabled = e;
			} else {
				a.dom.toggleClass('disabled', e || a.parentDisabled);
				a.disabled = e;
			}

			// 轮询所有子控件，并设置为相同disabled状态
			$('>li', a.ul).each(function(i, li) {
				$.each($(li).data('ctls'), function(k, ctl) {
					ctl.disable(fakeState, true);
				})
			})
		},

		bind : function(e, callback) {
		},

		setStyle : function(cssStyle) {
			this.dom.css(cssStyle);
		},

		update : function(data, compareCol) {
			var a = this, entity;
			$.each(data, function(i, v) {
				$('>li', a.ul).each(function(row, li) {
					li = $(li);
					entity = li.data('entity');
					if (entity && entity[compareCol] == v[compareCol]) {
						li.data('entity', v);
						$.each(li.data('ctls'), function(k, ctl) {
							if (ctl.profile.rl) {
								//console.log(ctl.profile.rl, ctl)
								ctl.val(v[ctl.profile.rl - 1]);
							}
						})
						if (a.custProp.xcmd) {
							a.instance.doCmd('P' + a.custProp.xcmd, {
								EVENT: {
									CTRL: a,
									LINE: li,
									X: row,
									GRIDROW: row + 1,
									ROWDATA: v
								}
							}, a.runtime, a.id)
						}
						return false;
					}
				})
			})
		},

		bindProperty: function(propertyName) {
			// 绑定了变量的控件，值改变时触发消息通知给实例
			var a = this;
			propertyName = propertyName.toLowerCase();
			a.bind('change', function(e){
				a.instance.fireValue(propertyName, a.runtime, a.evt(), a);
			});

			// 绑定值消息，当实例改变时，控件同步更新
			a.val(a.instance.getValue(propertyName, a.runtime));
			a.instance.bindValue(propertyName, a, function(e) {
				a.evt(e);
			});
		},

		scrolling : function(second) {
			var a = this;
			if (a.scrollThread)
				clearInterval(a.scrollThread);
			if (second > 0) {
				a.scrollThread = setInterval(function(){
					$('>li:last-child', a.ul).after($('>li:eq(0)', a.ul));
				}, second * 1000);
			}
		},

		destroy : function() {
		},
		getItem: function(e) {
			return this.attributes[e];
		},
		setItem: function(e, v) {
			this.attributes[e] = v;
			return this;
		}
	};


	/*
	 * 动态页面组件：Tab
	 */
	var cTab = function(container, profile, runtime, data, rowNum) {
		return new ctlTab(container, profile, runtime, data, rowNum);
	},

	ctlTab = function(container, profile, runtime, data, rowNum) {
		var a = this;
		a.id = profile.cId;
		a.type = "TAB";
		a.disabled = false;
		a.instance = runtime.instance;
		a.container = container;
		a.runtime = runtime;
		a.path = runtime.namespace + '.' + a.id;
		a.profile = profile;
		a.objProp = profile.ot || {};
		a.custProp = profile.o2 || {};
		a.xitemRow = rowNum;
		a.xitemData = data;
		a.changeCalls = [];
		a.parentDisabled = a.disabled = false;
		a.ctls = [];
		a.attributes = {};
		// console.log(a);

		var q = ctlStyle(a), style = q.style, outerStyle = q.outerStyle, innerStyle = q.innerStyle, clazz = q.clazz, autoHeight = (style['height'] == 'auto');
		a.dom = $('<div data-type="' + a.type + '" data-path="' + a.path + '" class="' + clazz.join(' ') + '" style="' + getStyles(style, outerStyle, innerStyle) + '" />').appendTo(container);
		if (parseInt(a.dom.css('flex-grow'))) {
			// 用于处理弹性布局
			if (a.dom.parent().css('flex-direction') == 'column') {
				a.dom.css('height', 'auto');
				autoHeight = true;
			} else
				a.dom.css('width', 'auto');
			a.box = $('<div class="wrapper" style="overflow:auto" />').appendTo(a.dom);
			a.tabDom = $('<div class="inner_box" style="position:relative;width:100%;height:100%" />').appendTo(a.box);
		} else {
			a.box = a.dom;
			var tabDomStyle = 'position:relative;';
			if (style['width'] !== 'auto')
				tabDomStyle += '; width:100%';
			if (style['height'] !== 'auto')
				tabDomStyle += '; height:100%';
			else
				autoHeight = true;
			a.tabDom = $('<div class="inner_box" style="' + tabDomStyle + '" />').appendTo(a.box);
		}

		var tabNav = $('<ul />').appendTo(a.tabDom), subs = a.objProp.sub;

		/*
		 * TAB特有OT属性中有：
			t:表示是固定TAB还是跟据SQL变化的TAB （0为固定，1为SQL动态）
			s:表示对应动态SQL的字段名或次序号中的TAB显示标签
			v:表示对应动态SQL的字段名或次序号中的TAB的对应ID值
			l:表示对应动态SQL的字段名或次序号中的TAB的对应的TYPE（与SUB中的lb对应,就显示对应的SUB中的那一个)
			sql:动态SQL
			sub:{
				type:0为组件，1为子页面
				bm:组件ID
				subP:子页面ID
				desc:如果是固定页，就是页标签
				cmdId:点击或离开执行的命令组
				lb:type(类型）
				img:图标
			}
		 */
		var drawContent = function(sub, tabId, container) {
			if (! container)
				container = $('<div id="' + tabId + '" />').appendTo(a.tabDom);

			container.data('draw', true).data('_dynControl', a);
			if (sub.bm) {
				// 内容为组件
				$D.drawCtls([{
					cId: a.id + '.' + sub.lb,
					cType: 24,
					cs : [ 0, 0, container.width(), container.height() ],
					lw: 0,
					ot: {
						zj: sub.bm
					},
					o2: {
						s_pos: 'relative',
						s_width: '100%',
						s_height: (autoHeight ? 'auto':'100%')
					}
				}], container, runtime)
				a.ctls = a.ctls.concat(container.data('controls'));
			} else if (sub.subP) {
				// 内容为子页面
				var page = $D.getPage(runtime, sub.subP);
				if (! page)
					$F.err('Ctls - Tab', '不存在的子页面：' + sub.subP);
				else {
					console.info('嵌套子页面：' + page.id)
					$D.drawCtls(page.ctls, container, runtime)
					a.ctls = a.ctls.concat(container.data('controls'));
					a.instance.afterDraw(runtime, page);
				}
			}
		};

		if (! a.objProp.t) {
			// 静态TAB控件
			var tabId, li, link;
			$.each(subs, function(i, sub) {
				// console.log(sub)
				tabId = a.id + '_' + i;
				li = $('<li data-ref="' + tabId + '" data-sub="' + sub.lb + '" />').appendTo(tabNav).data('entity', sub);
				link = $('<a href="javascript:;" data-ref="' + tabId + '" />').appendTo(li);
				if (sub.img)
					link.append($F.parseIcon(sub.img).addClass('pull-left'));
				link.append('<span>' + sub.desc + '</span>');
				if (a.custProp.preload)
					drawContent(sub, tabId);
			})
			a.tabs = a.tabDom.wisTab({
				autoHeight: autoHeight,
				vertical: a.custProp.direct,
				onUnselected: function(id, container, tab, callback) {
					var sub = tab.data('entity');
					if (sub.cmdId) {
						var R = {
								ID : tab.attr('data-sub'),
								TYPE : sub.lb,
								ACTIVE : false,
								process : callback
							};
						a.instance.doCmd('P' + sub.cmdId, {
							CTRL : a,
							EVENT : R
						}, runtime, a.id + '_' + sub.desc);
						if (! R.STOP)
							callback();
					} else
						callback();
				},
				onSelected: function(id, container, tab) {
					// console.log(id)
					var sub = tab.data('entity');
					// console.log(sub);
					if (sub.cmdId) {
						a.instance.doCmd('P' + sub.cmdId, {
							CTRL : a,
							EVENT : {
								ID : tab.attr('data-sub'),
								TYPE : sub.lb,
								ACTIVE : true
							}
						}, runtime, a.id + '_' + sub.desc);
					}
					if (! container.data('draw'))
						drawContent(sub, id, container);
				}
			});
		} else {
			// 动态TAB控件
			var getSub = function(tab) {
				for(var i=0; i<subs.length; i++) {
					if (subs[i].lb == tab[a.objProp.l])
						return subs[i];
				}
			},
			makeTabs = function(cs) {
				var tabId, li, link, sub;
				$.each(cs, function(i, tab) {
					sub = getSub(tab);
					if (! sub) {
						$F.err('Ctls - ctlTab', '不存在的面板类型');
					} else {
						tabId = a.id + '_' + sub.lb;
						li = $('<li data-ref="' + tabId + '" data-sub="' + tab[a.objProp.v] + '" />').appendTo(tabNav).data('entity', sub);
						link = $('<a href="javascript:;" data-ref="' + tabId + '" />').appendTo(li);
						if (sub.img)
							link.append($F.parseIcon(sub.img).addClass('pull-left'));
						link.append('<span>' + tab[a.objProp.s] + '</span>');
					}
				})
				a.tabs = a.tabDom.wisTab({
					autoHeight: autoHeight,
					vertical: a.custProp.direct,
					onUnselected: function(id, container, tab, callback) {
						var sub = tab.data('entity');
						if (sub.cmdId) {
							var R = {
									ID : tab.attr('data-sub'),
									TYPE : sub.lb,
									ACTIVE : false,
									process : callback
								};
							a.instance.doCmd('P' + sub.cmdId, {
								CTRL : a,
								EVENT : R
							}, runtime, a.id + '_' + sub.desc);
							if (! R.STOP)
								callback();
						} else
							callback();
					},
					onSelected: function(id, container, tab) {
						var sub = tab.data('entity');
						if (! container.data('draw'))
							drawContent(sub, id, container);
						if (sub.cmdId) {
							a.instance.doCmd('P' + sub.cmdId, {
								CTRL : a,
								EVENT : {
									ID : tab.attr('data-sub'),
									TYPE : sub.lb,
									ACTIVE : true
								}
							}, runtime, a.id + '_' + sub.desc);
						}
					}
				});
			},
			execute = function(sqlId, params) {
				a.runtime.sqlQueue[sqlId] = {
					structId : a.runtime.struct.id,
					params : params,
					callback : function(data) {
						var paramsStr = $F.display(params);
						if (data.count < 0) {
							$F.err('SQLExec - faild', 'DYN[' + a.runtime.struct.id + '] KEY[' + sqlId + '], 控件[' + a.type + '@' + a.id + '][PARAMS: ' + paramsStr + ']');
							data = $.extend({
								columns : [],
								fields : []
							}, data);
						} else {
							if ($E.debug)
								console.log('SQLExec - success', 'DYN[' + a.runtime.struct.id + '] KEY[' + sqlId + '], 控件[' + a.type + '@' + a.id + '][PARAMS: ' + paramsStr + ']');
						}
						var cs = sqldata(data, [ a.objProp.s, a.objProp.v, a.objProp.l ]);
						//console.log('Ctls - tab', '动态TAB控件重绘中', cs);
						makeTabs(cs);
					}
				}
				a.instance.sqlexec(a.runtime);
			};

			// 动态SQL取值
			var i = a.objProp.sql.indexOf('||');
			var sqlId = a.objProp.sql.substring(0, i), jsonStr = a.objProp.sql.substring(i+2), params = JSON.parse(jsonStr);
			for(var key in params) {
				var vn = params[key].toLowerCase();
				if (vn[0] == '@') {
					vn = parseInt(vn.substring(1)) - 1;
					params[key] = data[vn];
				} else {
					// 需要支持动态刷新
					params[key] = a.instance.getValue(vn, runtime);
					a.instance.bindValue(vn, a, function(e){
						params[key] = e.data;
						// 创建回调选项方法
						a.tabs.destroy();
						execute(sqlId, params);
					});
				}
			}
			execute(sqlId, params);
		}

		if (a.custProp.s_state)
			a.state(a.custProp.s_state);
		makeValueAndState(a, data, rowNum);
		return a;
	};

	ctlTab.prototype = {
		state : function(e) {
			if (e == undefined)
				return this._state;
			else {
				this._state = e;
				if (e == 1)
					this.dom.hide();
				else {
					this.dom.show();
					this.disable(e == 2);
				}
			}
		},
		disable: function(e, byParent) {
			if (byParent) {
				this.dom.toggleClass('disabled', e || this.disabled);
				this.parentDisabled = e;
			} else {
				this.dom.toggleClass('disabled', e || this.parentDisabled);
				this.disabled = e;
			}
		},

		val : function(t) {
			var a = this;
			if (t == undefined){
				return a.value;
			} else {
				a.value = t;
			}
		},
		evt : function(e) {
			var a = this;
			if (e == undefined) {
				return {
					type: 0,
					data: a.val()
				}
			} else {
				a.val(e.data);
			}
		},

		bind : function(e, callback) {
			if (e == 'change')
				this.changeCalls.push(callback);
		},

		triggerChange : function(e) {
			$.each(this.changeCalls, function(){
				this();
			})
		},

		active : function(e) {
			if (e < 1)
				$F.err('Ctls - Tab', '不合法的标签页号：' + e);
			this.tabs.active(e - 1);
		},
		getItem: function(e) {
			return this.attributes[e];
		},
		setItem: function(e, v) {
			this.attributes[e] = v;
			return this;
		}
	};

	/*
	 * 图标组件
	 */
	var cChart = function(container, profile, runtime, data, rowNum) {
		return new ctlChart(container, profile, runtime, data, rowNum);
	},

	ctlChart = function(container, profile, runtime, data, rowNum) {
		var a = this;
		a.id = profile.cId;
		a.type = "CHART";
		a.disabled = false;
		a.instance = runtime.instance;
		a.container = container;
		a.runtime = runtime;
		a.path = runtime.namespace + '.' + a.id;
		a.profile = profile;
		a.objProp = profile.ot || {};
		a.custProp = profile.o2 || {};
		a.xitemRow = rowNum;
		a.chart = undefined;
		a.chartType = ''; // 图表类型 highchart/echart
		a.attributes = {};
		//console.log(a);

		var q = ctlStyle(a), style = q.style, outerStyle = q.outerStyle, innerStyle = q.innerStyle, clazz = q.clazz;
		a.dom = $('<div data-type="' + a.type + '" data-path="' + a.path + '" class="' + clazz.join(' ') + '" style="' + getStyles(style, outerStyle, innerStyle) + '" />').appendTo(container);
		if (parseInt(a.dom.css('flex-grow'))) {
			// 用于处理弹性布局
			if (a.dom.parent().css('flex-direction') == 'column')
				a.dom.css('height', 'auto');
			else
				a.dom.css('width', 'auto');
			var fakebox = $('<div class="wrapper" />').appendTo(a.dom);
			a.box = $('<div style="width=100%;height:100%" />').appendTo(fakebox);
			fakebox.resize(function(e) {
				a.box.width(a.dom.width())
				a.box.height(a.dom.height())
			});
		} else {
			a.box = $('<div style="width=100%;height:100%" />').appendTo(a.dom);
			a.dom.resize(function(e) {
				a.box.width(a.dom.width())
				a.box.height(a.dom.height())
			});
		}

		a.libGuid = a.objProp.chartType;
		a.chartProps = {};
		$.each(a.objProp.property, function(i, v) {
			a.chartProps[v.proKey] = v.proValue
		})
		if (a.custProp.s_state)
			a.state(a.custProp.s_state);
		makeValueAndState(a, data, rowNum);
		return a;
	};

	ctlChart.prototype = {
		state : function(e) {
			if (e == undefined)
				return this._state;
			else {
				this._state = e;
				if (e == 1)
					this.dom.hide();
				else {
					this.dom.show();
				}
			}
		},
		disable : function(e, byParent) {
		},

		redraw : function() {
			var a = this;
			$EliteChart.getInstance(a.runtime.project).draw(a);
		},

		val : function(t) {
			var a = this;
			if (t == null || t == undefined)
				return a.value;
			else {
				if (a.value !== t) {
					a.value = t;
					if ($.type(t) == 'array' && t.length == 0) {
						$EliteChart.clear(a.box);
					}
					else{
						$EliteChart.getInstance(a.runtime.project).draw(a);
					}
				}
			}
			return a;
		},

		evt : function(e) {
			if (e == undefined)
				return {
					type : 0,
					data : this.val()
				}
			else
				this.val(e.data);
		},

		bind : function(e, callback) {
			if (e == 'click')
				this.clickCallback = callback;
		},

		setStyle : function(cssStyle) {
			this.dom.css(cssStyle);
		},

		refresh : function() {
			var a = this;
			$EliteChart.getInstance(a.runtime.project).draw(a);
		},

		/**
		 * 当tab切换到激活页面时 同是resize当前退保
		 */
		active : function() {
			if (this.chart) {
				this.resizeChart();
			}
		},

		resizeChart : function() {
			var a = this;
			if (a.chartType.match(/highchart/gi)) {
				a.chart && a.chart.reflow();
			} else if (a.chartType.match(/echart/gi)) {
				a.chart && a.chart.resize();
			}
		},

		setLineEvents : function(eventObj) {
			var a = this;
//			var eventObj = {click: function(e) {
//                console.log(e.point);
//                a.runtime.project.events.notify(listenerKey, e.point);
//            }};
			var plotOptions = a.chart.userOptions.plotOptions;
			if (plotOptions && plotOptions.line) {
				plotOptions.line.events = eventObj;
			} else if (plotOptions) {
				plotOptions.line = {
	                events: eventObj
				};
			} else {
				plotOptions = {
					line : {
		                events: eventObj
					}
				};
			}
			a.chart.update({plotOptions: plotOptions});
		},
		getItem: function(e) {
			return this.attributes[e];
		},
		setItem: function(e, v) {
			this.attributes[e] = v;
			return this;
		}
	};


	/*
	 * 图标组件
	 */
	var cChart2 = function(container, profile, runtime, data, rowNum) {
		return new ctlChart2(container, profile, runtime, data, rowNum);
	},

	ctlChart2 = function(container, profile, runtime, data, rowNum) {
		var a = this;
		a.id = profile.cId;
		a.type = "CHART-OLD";
		a.disabled = false;
		a.instance = runtime.instance;
		a.container = container;
		a.runtime = runtime;
		a.path = runtime.namespace + '.' + a.id;
		a.profile = profile;
		a.objProp = profile.ot || {};
		a.custProp = profile.o2 || {};
		a.xitemRow = rowNum;
		a.attributes = {};
		//console.log(a);

		var q = ctlStyle(a), style = q.style, outerStyle = q.outerStyle, innerStyle = q.innerStyle, clazz = q.clazz;
		a.dom = $('<div data-type="' + a.type + '" data-path="' + a.path + '" class="' + clazz.join(' ') + '" style="' + getStyles(style, outerStyle, innerStyle) + '" />').appendTo(container);
		if (parseInt(a.dom.css('flex-grow'))) {
			// 用于处理弹性布局
			if (a.dom.parent().css('flex-direction') == 'column')
				a.dom.css('height', 'auto');
			else
				a.dom.css('width', 'auto');
			var fakebox = $('<div class="wrapper" />').appendTo(a.dom);
			a.box = $('<div style="width=100%;height:100%" />').appendTo(fakebox);
			fakebox.resize(function(e) {
				a.box.width(a.dom.width())
				a.box.height(a.dom.height())
			});
		} else {
			a.box = $('<div style="width=100%;height:100%" />').appendTo(a.dom);
			a.dom.resize(function(e) {
				a.box.width(a.dom.width())
				a.box.height(a.dom.height())
			});
		}

		if (a.objProp) {
			if (a.objProp.cId == undefined)
				return a;
			if (a.objProp.x == undefined)
				a.objProp.x = 0;
			if (a.objProp.v == undefined)
				a.objProp.v = 0;
			if (a.objProp.trans == undefined)
				a.objProp.trans = 0;
			var subType = parseInt(a.objProp.cId);
			a.chartConfig = {
				type : subType,
				title : a.objProp.t || '',
				subTitle : a.objProp.t1 || '',
				alpha : a.objProp.d3a,
				beta : a.objProp.d3b,
				depth : a.objProp.d3d,
				xFormat : a.objProp.xf,
				yFormat : a.objProp.yf,
				theme : profile.sty,
				spacing : a.objProp.S4,
				margin : a.objProp.M4,
				border : a.objProp.ff,
				bgStyle : a.objProp.bks,
				exporting : false,
				legend : (a.custProp.legend > 0 ? false:true)
			}

			if (subType == 1 || subType == 3 || subType == 7 || subType == 11) {
				// 折线图、柱状图、条状图、混合图
				a.chartConfig = $.extend({
					yTitle : a.objProp.y || '',
					unit : a.objProp.u || '',
					transCol : a.objProp.trans,
					xCol : a.objProp.x,
					dataCol : a.objProp.v
				}, a.chartConfig);
			} else if (subType == 2 || subType == 8 || subType == 9) {
				// 饼图、锥形图、漏斗图
				a.chartConfig = $.extend({
					name : a.objProp.n || '',
					unit : a.objProp.u || '',
					showLabel : a.objProp.l,
					labelColor : a.objProp.dc,
					connectColor : a.objProp.lc,
					slice : a.objProp.s
				}, a.chartConfig);
			} else if (subType == 4 || subType == 10) {
				// 圆表图、半圆图
				a.chartConfig = $.extend({
					name : a.objProp.n || '',
					unit : a.objProp.u || '',
					showLabel : a.objProp.l,
					min : a.objProp.mi,
					max : a.objProp.mx,
					section : a.objProp.fd
				}, a.chartConfig);
			} else if (subType == 5) {
				// 三轴对比图
				a.chartConfig = $.extend({
					yTitle : a.objProp.ly || '',
					unit : a.objProp.lu || '',
					yTitle2 : a.objProp.ry || '',
					unit2 : a.objProp.ru || '',
					xCol : a.objProp.x,
					transCol : a.objProp.trans,
					dataCol : a.objProp.v,
					yFormat2 : a.objProp.yf2
				}, a.chartConfig);
			} else if (subType == 6) {
				// 时间轴图
				a.chartConfig = $.extend({
					yTitle : a.objProp.y || '',
					unit : a.objProp.u || '',
					xCol : a.objProp.x,
					dataCol : a.objProp.v
				}, a.chartConfig);
			} else {
				$F.err('Ctls - Chart', '尚未实现的图表类型：' + a.objProp.cId);
				//console.log(profile);
			}
		} else {
			$F.err('Ctls - Chart', '未定义的图表');
		}
		// console.info(a.chartConfig);

		if (a.custProp.s_state)
			a.state(a.custProp.s_state);
		makeValueAndState(a, data, rowNum);
		return a;
	};

	ctlChart2.prototype = {
		state : function(e) {
			if (e == undefined)
				return this._state;
			else {
				this._state = e;
				if (e == 1)
					this.dom.hide();
				else {
					this.dom.show();
				}
			}
		},
		disable : function(e, byParent) {
		},

		redraw : function() {
			var a = this;
			a.box.removeData('chartData');
			a.box.highcharts() && a.box.highcharts().destroy();
			Charts.draw(a, a, a.defaultOptions, a.chartConfig, a.clickCallback, a.box);
		},

		val : function(t) {
			var a = this;
			if (t == null || t == undefined)
				return a.value;
			else {
				if (a.value !== t) {
					a.value = t;
					if ($.type(t) == 'array' && t.length == 0) {
						a.box.removeData('chartData');
						a.box.highcharts() && a.box.highcharts().destroy();
					}
					else
						Charts.draw(a, t, a.defaultOptions, a.chartConfig, a.clickCallback, a.box);
				}
			}
			return a;
		},

		evt : function(e) {
			if (e == undefined)
				return {
					type : 0,
					data : this.val()
				}
			else
				this.val(e.data);
		},

		bind : function(e, callback) {
			if (e == 'click')
				this.clickCallback = callback;
		},

		setScript : function(script) {
			this.defaultOptions = script;
		},

		setStyle : function(cssStyle) {
			this.dom.css(cssStyle);
		},

		refresh : function() {
			var a = this;
			a.dom.highcharts().destroy();
			Charts.draw(a, a.value, a.defaultOptions, a.chartConfig, a.clickCallback, a.dom);
		},
		getItem: function(e) {
			return this.attributes[e];
		},
		setItem: function(e, v) {
			this.attributes[e] = v;
			return this;
		}
	};

	/*
	 * 自定义组件：Component
	 */
	var cComponent = function(container, profile, runtime) {
		return new ctlComponent(container, profile, runtime);
	},

	ctlComponent = function(container, profile, runtime) {
		var a = this;
		a.id = profile.cId;
		a.type = "COMPONENT";
		a.disabled = false;
		a.instance = runtime.instance;
		a.container = container;
		a.runtime = runtime;
		a.path = runtime.namespace + '.' + a.id;
		a.profile = profile;
		a.objProp = profile.ot || {};
		a.custProp = profile.o2 || {};
		a.parentDisabled = a.disabled = false;
		a.ctls = [];
		a.attributes = {};
		// console.log(a);

		var q = ctlStyle(a), style = q.style, outerStyle = q.outerStyle, innerStyle = q.innerStyle, clazz = q.clazz;
		if (a.custProp.shell == 2) {
			a.dom = a.box = a.container;
		} else {
			if (a.custProp.border)
				clazz.push('dyn_border')
			a.dom = $('<div data-type="' + a.type + '" data-path="' + a.path + '" class="' + clazz.join(' ') + '" style="' + getStyles(style, outerStyle, innerStyle) + '" />').appendTo(container);
			if (parseInt(a.dom.css('flex-grow'))) {
				// 用于处理弹性布局
				if (a.dom.parent().css('flex-direction') == 'column')
					a.dom.css('height', 'auto');
				else
					a.dom.css('width', 'auto');
				//a.box = $('<div class="wrapper" style="overflow:auto" />').appendTo(a.dom);
				a.box = a.dom;
			} else {
				a.box = a.dom;
			}
		}
		a.box.data('_dynControl', a)

		if (a.objProp.zj)
			a.componentId = a.objProp.zj;

		if (a.custProp.s_state)
			a.state(a.custProp.s_state);
		makeValueAndState(a);
		return a;
	};

	ctlComponent.prototype = {
		state : function(e) {
			if (e == undefined)
				return this._state;
			else {
				if (this.custProp.shell !== 2) {
					this._state = e;
					if (e == 1)
						this.dom.hide();
					else {
						this.dom.show();
					}
					this.disable(e == 2);
				}
			}
		},
		disable : function(e, byParent) {
			var a = this, fakeState = e;
			if (byParent) {
				fakeState = e || a.disabled;
				a.dom.toggleClass('disabled', e || a.disabled);
				a.parentDisabled = e;
			} else {
				a.dom.toggleClass('disabled', e || a.parentDisabled);
				a.disabled = e;
			}
			// 轮询所有子控件，并设置为相同disabled状态
			$.each(a.ctls, function(i, v){
				v.disable(fakeState, true);
			})
		},

		val : function(t) {
			var a = this;
			if (t == null || t == undefined)
				return a.value;
			else {
				if (a.value !== t) {
					a.value = t;
				}
			}
			return a;
		},

		evt : function(e) {
			if (e == undefined)
				return {
					type : 0,
					data : this.val()
				}
			else
				this.val(e.data);
		},
		bind: function(e, callback) {
		},
		getContainer : function() {
			return this.box;
		},

		setStyle : function(cssStyle) {
			if (this.custProp.shell == 2)
				return;

			this.dom.css(cssStyle);
		},

		bindProperty : function(propertyName) {
			this.bindPropertyName = propertyName;
		},

		fireBindProperty : function(e, type) {
			this.instance.fireValue(this.bindPropertyName, this.runtime, {
				type: type || 0,
				data: e
			}, this);
		},

		initCmd : function(component) {
			var a = this, cmd = a.custProp.initcmd;
			a.component = component;
			a.dom.attr('data-com2', component.struct.GroupIdA);
			a.component.init();
			if (cmd) {
				a.instance.doCmd('P' + cmd, {
					CTRL: a,
					COMPONENT: component
				}, a.runtime, a.id);
			}
		},

		attr : function(key, value) {
			var a = this;
			if (a.component)
				a.component.attr(key, value);
			else {
				a.attributes = a.attributes || {};
				a.attributes[key] = value;
			}
		},
		getItem: function(e) {
			return this.attributes[e];
		},
		setItem: function(e, v) {
			this.attributes[e] = v;
			return this;
		}
	};

	/*
	 * 自定义组件：LayoutBox
	 */
	var cLayoutBox = function(container, profile, runtime) {
		return new ctlLayoutBox(container, profile, runtime);
	},

	ctlLayoutBox = function(container, profile, runtime) {
		var a = this;
		a.id = profile.cId;
		a.type = "LAYOUT";
		a.disabled = false;
		a.instance = runtime.instance;
		a.container = container;
		a.runtime = runtime;
		a.path = (runtime.namespace ? (runtime.namespace + '.' + a.id) : a.id);
		a.profile = profile;
		a.objProp = profile.ot || {};
		a.custProp = profile.o2 || {};
		a.parentDisabled = a.disabled = false;
		a.ctls = [];
		a.attributes = {};
		//console.log(a);

		var q = ctlStyle(a), style = q.style, outerStyle = q.outerStyle, innerStyle = q.innerStyle, clazz = q.clazz;
		clazz.push('ui-helper-clearfix');
		a.dom = $('<div data-type="' + a.type + '" data-id="' + a.id + '" data-path="' + a.path + '" class="' + clazz.join(' ') + '" style="' + getStyles(style, outerStyle, innerStyle) + '" />').appendTo(container);
		if (parseInt(a.dom.css('flex-grow'))) {
			// 用于处理弹性布局
			if (a.dom.parent().css('flex-direction') == 'column')
				a.dom.css('height', 'auto');
			else
				a.dom.css('width', 'auto');
			a.box = $('<div class="wrapper" style="overflow:auto" />').appendTo(a.dom);
			a.box = $('<div class="inner_box" style="position:relative;width:100%;height:100%" />').appendTo(a.box);
		} else {
			if (a.dom.css('position') == 'absolute') {
				a.box = $('<div class="inner_box" style="position:relative" />').appendTo(a.dom);
				if (style['width'] !== 'auto')
					a.box.css('width', '100%');
				if (style['height'] !== 'auto')
					a.box.css('height', '100%');
			} else
				a.box = a.dom;
		}

		// Read personalize data of layout
		a.perzArr = [];
		$F.dataService('SystemDo2', {
			data: {
				token: runtime.project.token,
				dbPool: '',
				sqls: [{
					key: 'Dyn.layout.read',
					params: {
						C1: $E.staff.epidSql,
						C2: $E.staff.id,
						C3: a.path
					}
				}, {
					key: 'Dyn.layout.read',
					params: {
						C1: $E.staff.epidSql,
						C2: '_DEFT_',
						C3: a.path
					}
				}]
			},
			async: false,
			digest: runtime.project.digest,
			success: function(data) {
				if (data.code > 0) {
					//console.log(data);
					if (data.value[0].count < 0) {
						$F.err('Ctls - layoutBox', 'Sql execute failed: ' + data.value[0].key);
						return;
					}
					a.perzArr = $F.makeJsonArray(data.value[0]);
					if (a.perzArr.length == 0) {
						// 当前账号无数据，从系统读入默认配置
						if (data.value[1].count < 0) {
							$F.err('Ctls - layoutBox', 'Sql execute failed: ' + data.value[1].key);
							return;
						}
						a.perzArr = $F.makeJsonArray(data.value[1]);
					}
				} else
					$F.err('Ctls - layoutBox', data.message);
			}
		})

		// 读取容器内置的组件列表
		var comLists = profile.ot || [];
		console.info('获取容器组件列表: ' + a.path, comLists)

		// 如果自定义数据中没有数据，则采用容器默认的组件属性进行UI处理
		if (a.perzArr.length == 0 && (a.custProp.stack == 1 || a.custProp.stack == 2)) {
			for(var key in comLists) {
				if (! comLists[key].o2)
					comLists[key].o2 = {};
				if (comLists[key].o2.defhide)
					continue;
				a.perzArr.push({
					STAFFID: $E.staff.id,
					COMKEY: key,
					COMID: comLists[key].ida,
					COMPNAME: comLists[key].name,
					X: 1,
					Y: 1,
					COLSPAN: 1,
					ROWSPAN: 1,
					TABINDEX: (comLists[key].o2.defidx || 0)
				})
			}
			a.perzArr.sort(function(a, b) {
				return a.TABINDEX > b.TABINDEX;
			})
			//console.info(a.perzArr);
		}
		//console.log('获取容器自定义数据：' + a.path, a.perzArr);
		// console.log(comLists)

		var visualCtl = [];
		if (a.custProp.stack == 1) {
			// 可堆叠容器
			var ul = $('<ul />').appendTo(a.box), li, pid;
			$.each(a.perzArr, function(i, perz){
				// console.info(perz);
				if (perz.COMKEY == 'CONTAINER' || ! comLists[perz.COMKEY])
					return;
				pid = runtime.project.id + '_' + a.id + '_' + perz.COMKEY;
				li = $('<li data-ref="' + pid + '" />').appendTo(ul).data('perz', perz);
				li.append('<a href="javascript:;" data-ref="' + pid + '">' + perz.COMPNAME + '</a>');

				if (a.custProp.preload) {
					var div = $('<div id="' + pid + '" />').appendTo(a.box).data('_dynControl', a);;
					perz.show = true;
					var vc = {
						cId : a.id + '.' + perz.COMKEY,
						cType: 24,
						cs : [ 0, 0, div.width() * 15, div.height() * 15 ],
						lw: 0,
						ot: {
							zj: comLists[perz.COMKEY].ida
						},
						o2: {
							s_width: '100%',
							s_height: '100%'
						},
						sty : comLists[perz.COMKEY].o2.s_class
					};
					var extend = comLists[perz.COMKEY].o2;
					for(var key in extend) {
						if (extend.hasOwnProperty(key))
							vc.o2[key] = extend[key];
					}
					$D.drawCtls([vc], div, runtime);
					a.ctls = a.ctls.concat(div.data('controls'));
				}
			})
			a.box.wisTab({
				vertical: a.custProp.direct,
				onSelected: function(id, container, tab) {
					var perz = tab.data('perz');
					if (! perz.show) {
						perz.show = true;
						var vc = {
							cId : a.id + '.' + perz.COMKEY,
							cType: 24,
							cs : [ 0, 0, container.width() * 15, container.height() * 15 ],
							lw: 0,
							ot: {
								zj: comLists[perz.COMKEY].ida
							},
							o2: {
								s_width: '100%',
								s_height: '100%'
							},
							sty : comLists[perz.COMKEY].o2.s_class
						};
						var extend = comLists[perz.COMKEY].o2;
						for(var key in extend) {
							if (extend.hasOwnProperty(key))
								vc.o2[key] = extend[key];
						}
						container.data('_dynControl', a);
						$D.drawCtls([vc], container, runtime);
						a.ctls = a.ctls.concat(container.data('controls'))
					} else {
						var comp = CtlUtils.findComponentById(runtime, perz.COMID);
						if (comp)
							comp.onActive();
					}
				}
			});
		} else if (a.custProp.stack == 2) {
			// 陈列式容器
			$.each(a.perzArr, function(i, perz){
				if (perz.COMKEY == 'CONTAINER' || ! comLists[perz.COMKEY])
					return;
				var vc = {
					cId : a.id + '.' + perz.COMKEY,
					cType : 24,
					cs : [ 0, 0, 0, 0],
					lw : 0,
					ot : {
						zj : comLists[perz.COMKEY].ida
					},
					o2 : {
						's_pos' : 'relative',
						's_height' : 'auto'
					},
					sty : comLists[perz.COMKEY].o2.s_class
				}
				var extend = comLists[perz.COMKEY].o2;
				for(var key in extend) {
					if (extend.hasOwnProperty(key)) {
						if (key == 'stateProp')
							vc.sV = extend[key];
						else
							vc.o2[key] = extend[key];
					}
				}

				if (! a.custProp.direct) {
					if (! vc.o2['s_display'])
						vc.o2['s_display'] = 'inline-block';
					vc.o2['s_width'] = 'auto';
					if (i > 0 && a.custProp.line)
						vc.csy = 'margin-left:' + a.custProp.line + 'px';
				} else {
					vc.o2['s_width'] = '100%';
					vc.o2['s_height'] = 'auto';
					if (i > 0 && a.custProp.line)
						vc.csy = 'margin-top:' + a.custProp.line + 'px';
				}
				visualCtl.push(vc);
			})
			if (visualCtl.length > 0) {
				a.box.data('_dynControl', a);
				$D.drawCtls(visualCtl, a.box, runtime);
				a.ctls = a.box.data('controls');
			} else {
				if (! a.custProp.locked) {
					var masker = $('<div class="dyn_layout"></a>').appendTo(a.box);
					$('<button title="' + $F.lang('ctls.layout.config') + '" type="button"><i class="far fa-2x fa-cog fa-spin" /></button>').appendTo(masker)
						.click(function(){
							// masker.remove();
							$E.openPlugin($F.lang('ctls.layout.plugin'), runtime.project, 'PerzComps', '', a);
						});
				}
			}
		} else {
			// 网格式容器
			if (a.custProp.constrain) {
				// 等比约束
				var totalUnit = 0;
				$.each(a.perzArr, function(i, perz){
					if (perz.COMKEY == 'CONTAINER' || !comLists[perz.COMKEY] || perz.COMID !== comLists[perz.COMKEY].ida)
						return;
					totalUnit = Math.max(perz.X - 1 + perz.COLSPAN, totalUnit);
				})
				//console.log('网格式布局检测到横向单元格总数为：' + totalUnit);
				$.each(a.perzArr, function(i, perz){
					// console.info(perz);
					if (perz.COMKEY == 'CONTAINER') {
						//  配置为容器高度
						//if (a.box.height() == 0) {
							a.box.css('height', perz.Y);
							a.box.css('minWidth', totalUnit*50 + 'px')
						//}
					} else {
						if (! comLists[perz.COMKEY])
							return;
						if (perz.COMID !== comLists[perz.COMKEY].ida) {
							//console.log('容器配置已更新，丢弃自定义配置：', perz);
							return;
						}
						var vc = {
							cId: a.id + '.' + perz.COMKEY,
							cType: 24,
							_percentSize: {
								left: ((perz.X - 1) * 100 / totalUnit) + '%',
								top: (perz.Y - 1) * 32,
								width: (perz.COLSPAN * 100 / totalUnit) + '%',
								height: perz.ROWSPAN * 30 + (perz.ROWSPAN - 1) * 2
							},
							cs: [0, 0, 0, 0],
							lw: 0,
							ot: {
								zj: comLists[perz.COMKEY].ida
							},
							o2: {
							},
							sty : comLists[perz.COMKEY].o2.s_class
						}
						var extend = comLists[perz.COMKEY].o2;
						for(var key in extend) {
							if (extend.hasOwnProperty(key))
								vc.o2[key] = extend[key];
						}
						visualCtl.push(vc);
					}
				})
			} else {
				$.each(a.perzArr, function(i, perz){
					// console.info(perz);
					if (perz.COMKEY == 'CONTAINER') {
						//  配置为容器高度
						//if (style['height'] == 'auto') {
							a.box.css('height', perz.Y);
						//}
					} else {
						if (! comLists[perz.COMKEY])
							return;
						if (perz.COMID !== comLists[perz.COMKEY].ida) {
							//console.log('容器配置已更新，丢弃自定义配置：', perz);
							return;
						}
						var vc = {
							cId: a.id + '.' + perz.COMKEY,
							cType: 24,
							cs : [ ((perz.X - 1) * 52 * 15), ((perz.Y - 1) * 32 * 15), ((perz.COLSPAN * 50 + (perz.COLSPAN - 1) * 2) * 15), ((perz.ROWSPAN * 30 + (perz.ROWSPAN - 1) * 2) * 15) ],
							lw: 0,
							ot: {
								zj: comLists[perz.COMKEY].ida
							},
							o2: {
							},
							sty : comLists[perz.COMKEY].o2.s_class
						}
						var extend = comLists[perz.COMKEY].o2;
						for(var key in extend) {
							if (extend.hasOwnProperty(key))
								vc.o2[key] = extend[key];
						}
						visualCtl.push(vc);
					}
				})
			}
			if (visualCtl.length > 0) {
				a.box.data('_dynControl', a);
				$D.drawCtls(visualCtl, a.box, runtime);
				a.ctls = a.box.data('controls');
			} else {
				if (! a.custProp.locked) {
					var masker = $('<div class="dyn_layout"></a>').appendTo(a.box);
					$('<button title="' + $F.lang('ctls.layout.config') + '" type="button"><i class="far fa-2x fa-cog fa-spin" /></button>').appendTo(masker)
						.click(function(){
							// masker.remove();
							$E.openPlugin($F.lang('ctls.layout.plugin'), runtime.project, 'PerzComps', '', a);
						});
				}
			}
		}

		if (! a.custProp.locked) {
			a.box.on('mousemove', function(e){
				if (e.ctrlKey && e.shiftKey) {
					// 按下了Ctrl键
					var masker = $('.dyn_layout_masker', a.dom);
					if (masker.length == 0) {
						masker = $('<div class="dyn_layout_masker unselectable"></div>').appendTo(a.dom);
						var of = a.dom.css('overflow');
						a.dom.css('overflow', 'hidden');
						$('<button title="' + $F.lang('ctls.layout.config') + '" type="button"><i class="far fa-2x fa-cog fa-spin" /></button>').appendTo(masker)
							.click(function(){
								masker.remove();
								a.dom.css('overflow', of);
								$E.openPlugin($F.lang('ctls.layout.plugin'), runtime.project, 'PerzComps', '', a);
							});
						$('<button title="' + $F.lang('ctls.layout.exit') + '" type="button"><i class="far fa-2x fa-sign-out-alt" /></button>').appendTo(masker)
							.click(function(){
								masker.remove();
								a.dom.css('overflow', of);
							});
					}
				}
			})
		}

		if (a.custProp.s_state)
			a.state(a.custProp.s_state);
		makeValueAndState(a);
		return a;
	};

	ctlLayoutBox.prototype = {
		state : function(e) {
			if (e == undefined)
				return this._state;
			else {
				this._state = e;
				if (e == 1)
					this.dom.hide();
				else {
					this.dom.show();
				}
			}
		},
		disable : function(e, byParent) {
			var a = this, fakeState = e;
			if (byParent) {
				fakeState = e || a.disabled;
				a.dom.toggleClass('disabled', e || a.disabled);
				a.parentDisabled = e;
			} else {
				a.dom.toggleClass('disabled', e || a.parentDisabled);
				a.disabled = e;
			}
			// 轮询所有子控件，并设置为相同disabled状态
			$.each(a.ctls, function(i, ctl){
				ctl.disable(fakeState, true);
			})
		},
		val : function(t) {
			var a = this;
			if (t == null || t == undefined)
				return a.value;
			else {
				if (a.value !== t) {
					a.value = t;
				}
			}
			return a;
		},
		evt : function(e) {
			if (e == undefined)
				return {
					type : 0,
					data : this.val()
				}
			else
				this.val(e.data);
		},
		bind: function(e, callback) {
		},
		setStyle : function(cssStyle) {
			this.dom.css(cssStyle);
		},
		getItem: function(e) {
			return this.attributes[e];
		},
		setItem: function(e, v) {
			this.attributes[e] = v;
			return this;
		}
	};

	/*
	 * 动态页面组件：Action
	 */
	var cAction = function(runtime) {
		return new ctlAction(runtime);
	},

	ctlAction = function(runtime) {
		var a = this;
		a.disabled = false;
		a.id = Guid.raw();
		a.type = 'ACTIONS';

		if (runtime.instance.getValue('var.act_hide', runtime, 0) == 1)
			return;

		$('.dyn_actions', runtime.container).remove();
		var actions = $('<div class="dyn_actions" />')
			.appendTo(runtime.container)
			.draggable({
				containment: runtime.container
			}),
			prev = $('<button class="ms">' + $F.lang('nav.prev') + '</button>').appendTo(actions),
			prevFlag = true,
			next = $('<button class="ms">' + $F.lang('nav.next') + '</button>').appendTo(actions),
			nextFlag = true,
			save = $('<button class="green">' + $F.lang('nav.save') + '</button>').appendTo(actions),
			saveFlag = true;
			//cancel = $('<button class="ms">取消</button>').appendTo(actions);

		next.click(function(e){
			$F.process(function(){
				$D.nextStep(runtime);
			})
		})
		prev.click(function(e){
			$F.process(function(){
				$D.prevStep(runtime);
			})
		})
		save.click(function(e){
			$F.process(function(){
				var r = runtime.instance.save();
				$F.notify(r>0? $F.lang('message.savesuccess'): $F.lang('message.savefailed'), r);
			})
		})

		var switchActions = function() {
			if (prevFlag || nextFlag || saveFlag)
				actions.show();
			else
				actions.hide();
		}

		if (runtime.data.local['var'] !== undefined && runtime.data.local['var']['act_hideprev'] !== undefined) {
			runtime.instance.bindValue('var.act_hideprev', {id:runtime.instance.id, runtime:runtime}, function(e) {
				if (e.data == 1) {
					prev.hide();
					prevFlag = false;
				} else {
					prev.show();
					prevFlag = true;
				}
				switchActions();
			});
		}
		if (runtime.flows.length < 2 || runtime.instance.getValue('var.act_hideprev', runtime, 0) == 1) {
			prev.hide();
			prevFlag = false;
		}

		if (runtime.data.local['var'] !== undefined && runtime.data.local['var']['act_hidenext'] !== undefined) {
			runtime.instance.bindValue('var.act_hidenext', {id:runtime.instance.id, runtime:runtime}, function(e) {
				if (e.data == 1) {
					next.hide();
					nextFlag = false;
				} else {
					next.show();
					nextFlag = true;
				}
				switchActions();
			});
		}
		if (! $D.hasNextPage(runtime) || runtime.instance.getValue('var.act_hidenext', runtime, 0) == 1) {
			next.hide();
			nextFlag = false;
		}

		if (runtime.data.local['var'] !== undefined && runtime.data.local['var']['act_hidesave'] !== undefined) {
			runtime.instance.bindValue('var.act_hidesave', {id:runtime.instance.id, runtime:runtime}, function(e) {
				if (e.data == 1) {
					save.hide();
					saveFlag = false;
				} else {
					save.show();
					saveFlag = true;
				}
				switchActions();
			});
		}
		if (runtime.instance.getValue('var.act_hidesave', runtime, 0) == 1 || ! runtime.instance.stateful || runtime.instance.inner) {
			save.hide();
			saveFlag = false;
		}
		switchActions();
	};

	ctlAction.prototype = {
		state : function(e) {
			if (e == 1)
				this.actions.hide();
			else {
				this.actions.show();
				this.disable(e == 2);
			}
		},
		disable: function(e, byParent) {
		},
	};

	return {
		version : '1.0.20170509',
		label : cLabel,
		timeline : cTimeline,
		number : cNumber,
		pin : cPin,
		text : cText,
		combox : cCombox,
		link : cLink,
		lol : cLol,
		button : cButton,
		checkbox : cCheckbox,
		radio : cRadio,
		table : cTable,
		table2 : cTable2,
		tree : cTree,
		list : cList,
		listci : cListci,
		datetime : cDatetime,
		calendar : cCalendar,
		panel : cPanel,
		page : cPage,
		script : cScript,
		progress : cProgress,
		image : cImage,
		audio : cAudio,
		video : cVideo,
		iframe : cIFrame,
		xitem : cXItem,
		splitter : cSplitter,
		chart : cChart,
		chart2 : cChart2,
		bsmenu : cBSMenu,
		tab : cTab,
		component : cComponent,
		layoutBox : cLayoutBox,
		action : cAction
	};
});
